Compare commits

...

1759 Commits

Author SHA1 Message Date
Grégoire Paris
17500f56ea Merge pull request #10923 from kaznovac/patch-1
basic-mapping: fix new-line rendered in output
2023-08-27 20:21:56 +02:00
Marko Kaznovac
fc2f724e2d basic-mapping: fix new-line rendered in output 2023-08-27 19:17:04 +02:00
Grégoire Paris
2f9e98754b Merge pull request #10915 from mpdude/post-events-later
Mitigate problems with `EntityManager::flush()` reentrance since 2.16.0 (Take 2)
2023-08-25 07:47:25 +02:00
Sergii Dolgushev
bb5524099c Use required classes for Lifecycle Callback examples (#10916)
* Use required classes for Lifecycle Callback examples

* Coding Style fixes

---------

Co-authored-by: Sergii Dolgushev <Sergii.Dolgushev@secondwaveds.com>
2023-08-23 22:47:15 +02:00
Grégoire Paris
3a8cafe228 Add space before backquote (#10918)
According to the RST docs,

> [inline markup] it must be separated from surrounding text by non-word
> characters. Use a backslash escaped space to work around that: thisis\ *one*\ word.

Because we were missing a space before backquotes here, the links were
not rendered. Escaping the space allow not to actually produce a space
in the output.

See https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#inline-markup
2023-08-23 21:42:35 +02:00
Matthias Pigulla
8259a16681 Mitigate problems with EntityManager::flush() reentrance since 2.16.0 (Take 2)
The changes from #10547, which landed in 2.16.0, cause problems for users calling `EntityManager::flush()` from within `postPersist` event listeners.

* When `UnitOfWork::commit()` is re-entered, the "inner" (reentrant) call will start working through all changesets. Eventually, it finishes with all insertions being performed and `UoW::$entityInsertions` being empty. After return, the entity insertion order, an array computed at the beginning of `UnitOfWork::executeInserts()`, still contains entities that now have been processed already. This leads to a strange-looking SQL error where the number of parameters used does not match the number of parameters bound. This has been reported as #10869.

* The fixes made to the commit order computation may lead to a different entity insertion order than previously. `postPersist` listener code may be affected by this when accessing generated IDs for other entities than the one the event has been dispatched for. This ID may not yet be available when the insertion order is different from the one that was used before 2.16. This has been mentioned in https://github.com/doctrine/orm/pull/10906#issuecomment-1682417987.

This PR suggests to address both issues by dispatching the `postPersist` event only after _all_ new entities have their rows inserted into the database. Likewise, dispatch `postRemove` only after _all_ deletions have been executed.

This solves the first issue because the sequence of insertions or deletions has been processed completely _before_ we start calling event listeners. This way, potential changes made by listeners will no longer be relevant.

Regarding the second issue, I think deferring `postPersist` a bit until _all_ entities have been inserted does not violate any promises given, hence is not a BC break. In 2.15, this event was raised after all insertions _for a particular class_ had been processed - so, it was never an "immediate" event for every single entity. #10547 moved the event handling to directly after every single insertion. Now, this PR moves it back a bit to after _all_ insertions.
2023-08-23 07:55:21 +02:00
David Arenas
5577d51c44 Add back throws annotation to getSingleScalarResult (#10907)
Fix regression introduced in #10870

`$result = $this->execute(null, $hydrationMode);` in `getSingleResult` can still throw NoResultException exception.
2023-08-13 13:01:30 +02:00
Eduardo Rocha
d1922a3065 Fix link on known issues docs (#10904) 2023-08-10 21:41:31 +02:00
Alexander M. Turek
597a63a86c PHPStan 1.10.28, Psalm 5.14.1 (#10895) 2023-08-09 15:05:08 +02:00
Bei Xiao
6b220e3c90 Fix return type of getSingleScalarResult (#10870) 2023-08-09 11:42:00 +02:00
Matthias Pigulla
6de4b68705 Use a dedicated exception for the check added in #10785 (#10881)
This adds a dedicated exception for the case that objects with colliding identities are to be put into the identity map.

Implements #10872.
2023-08-09 11:38:35 +02:00
Matthias Pigulla
16c0151831 Document more clearly that the insert order is an implementation detail (#10883) 2023-08-09 11:36:05 +02:00
Matthias Pigulla
440b244ebc Fix broken changeset computation for entities loaded through fetch=EAGER + using inheritance (#10884)
#10880 reports a case where the changes from #10785 cause entity updates to be missed.

Upon closer inspection, this change seems to be causing it:

https://github.com/doctrine/orm/pull/10785/files#diff-55a900494fc8033ab498c53929716caf0aa39d6bdd7058e7d256787a24412ee4L2990-L3003

The code was changed to use `registerManaged()` instead, which basically does the same things, but (since #10785) also includes an additional check against duplicate entity instances.

But, one detail slipped through tests and reviews: `registerManaged()` also updates `\Doctrine\ORM\UnitOfWork::$originalEntityData`, which is used to compute entity changesets. An empty array `[]` was passed for $data here.

This will make the changeset computation assume that a partial object was loaded and effectively ignore all field updates here:

a616914887/lib/Doctrine/ORM/UnitOfWork.php (L762-L764)

I think that, effectively, it is sufficient to call `registerManaged()` only in the two cases where a proxy was created.

Calling `registerManaged()` with `[]` as data for a proxy object is consistent with e. g. `\Doctrine\ORM\EntityManager::getReference()`.

In the case that a full entity has to be loaded, we need not call `registerManaged()` at all, since that will already happen inside `EntityManager::find()` (or, more specifically, `UnitOfWork::createEntity()` called inside it).

Note that the test case has to make some provisions so that we actually reach this case:
* Load an entity that uses `fetch="EAGER"` on a to-one association
* That association being against a class that uses inheritance (why's that?)
2023-08-09 11:34:53 +02:00
Matthias Pigulla
a616914887 Turn identity map collisions from exception to deprecation notice (#10878)
In #10785, a check was added that prevents entity instances from getting into the identity map when another object for the same ID is already being tracked.

This caused regressions for users that work with application-provided IDs and expect this condition to fail with `UniqueConstraintViolationExceptions` when flushing to the database.

Thus, this PR turns the exception into a deprecation notice. Users can opt-in to the new behavior. In 3.0, the exception will be used.

Implements #10871.
2023-08-04 14:06:02 +02:00
Dieter Beck
fd0bdc69b0 Add possibility to set reportFieldsWhereDeclared to true in ORMSetup (#10865)
Otherwise it is impossible to avoid a deprecation warning when using ORMSetup::createAttributeMetadataConfiguration()
2023-08-02 14:34:13 +02:00
Michael Olšavský
f50803ccb9 Fix UnitOfWork->originalEntityData is missing not-modified collections after computeChangeSet (#9301)
* Fix original data incomplete after flush

* Apply suggestions from code review

Co-authored-by: Alexander M. Turek <me@derrabus.de>

---------

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2023-08-02 13:44:15 +02:00
Matthias Pigulla
eeefc6bc0f Add an UPGRADE notice about the potential changes in commit order (#10866) 2023-08-02 13:42:49 +02:00
Grégoire Paris
710dde83aa Update branch metadata (#10862) 2023-08-01 14:56:34 +02:00
Grégoire Paris
495cd06b9a Merge pull request #10727 from derrabus/revert/symfony-7
Revert "Allow symfony/console 7"
2023-08-01 14:07:04 +02:00
Grégoire Paris
fd7a14ad22 Merge pull request #10547 from mpdude/commit-order-entity-level
Compute the commit order (inserts/deletes) on the entity level
2023-08-01 09:21:09 +02:00
Matthias Pigulla
0d3ce5d4f8 Exclude deprecated classes from Psalm checks (until 3.0) 2023-08-01 08:53:56 +02:00
Matthias Pigulla
f01d107edc Fix commit order computation for self-referencing entities with application-provided IDs
This excludes such associations from the commit order computation, since the foreign key constraint will be satisfied when inserting the row.

See https://github.com/doctrine/orm/pull/10735/ for more details about this edge case.
2023-08-01 08:43:16 +02:00
Alexander M. Turek
3cc30c4024 Merge branch '2.15.x' into 2.16.x
* 2.15.x:
  Fix static analysis
  Other solution
  Avoid self deprecation
  fix: use platform options instead of deprecated custom options (#10855)
2023-07-28 16:26:45 +02:00
Alexander M. Turek
d2de4ec03c Revert "Introduce FilterCollection#restore method (#10537)"
This reverts commit 8e20e1598e.
2023-07-28 16:08:17 +02:00
Vincent Langlet
64ee76e94e Introduce FilterCollection#restore method (#10537)
* Introduce FilterCollection#restore method

* Add suspend method instead

* Add more tests
2023-07-28 16:08:06 +02:00
Vincent Langlet
8e20e1598e Introduce FilterCollection#restore method (#10537)
* Introduce FilterCollection#restore method

* Add suspend method instead

* Add more tests
2023-07-28 16:05:51 +02:00
Grégoire Paris
24df74d61d Merge pull request #10856 from VincentLanglet/fixDeprecation
Fix/Self deprecation with getQueryCacheImpl
2023-07-26 23:41:39 +02:00
Vincent Langlet
442f073d25 Fix static analysis 2023-07-26 17:42:20 +02:00
Vincent Langlet
a5161e9485 Other solution 2023-07-26 16:00:37 +02:00
Vincent Langlet
ddc7d953b9 Avoid self deprecation 2023-07-26 12:37:42 +02:00
Kévin Dunglas
db51ed4f4c fix: use platform options instead of deprecated custom options (#10855) 2023-07-25 16:23:46 +02:00
Alexander M. Turek
6d27797b2e Merge release 2.15.4 into 2.16.x (#10850) 2023-07-23 23:49:30 +02:00
Nicolas Grekas
89250b8ca2 Use properties instead of getters to read property/class names via reflection (#10848) 2023-07-20 20:37:52 +02:00
Grégoire Paris
f7e4b61459 Merge pull request #10847 from greg0ire/remove-toc 2023-07-18 09:50:04 +02:00
Grégoire Paris
6b0afdbd58 Avoid triple colons
It confuses the guides, and is ugly.
2023-07-18 08:57:09 +02:00
Grégoire Paris
d3cf17b26d Remove toc
We already have the sidebar for this.
2023-07-18 08:56:24 +02:00
Alexander M. Turek
bc61d7d21e Merge branch '2.15.x' into 2.16.x
* 2.15.x:
  PHPStan 1.10.25, Psalm 5.13.1 (#10842)
2023-07-16 23:40:09 +02:00
Alexander M. Turek
5213228a64 PHPStan 1.10.25, Psalm 5.13.1 (#10842) 2023-07-16 23:38:29 +02:00
Nicolas Grekas
dca7ddf969 Decouple public API from Doctrine\Persistence\Proxy (#10832) 2023-07-15 10:55:35 +02:00
Grégoire Paris
e781639812 Merge pull request #10841 from doctrine/2.15.x 2023-07-12 15:54:17 +02:00
Grégoire Paris
7848417488 Merge pull request #10838 from greg0ire/remove-dummy-title 2023-07-12 11:07:46 +02:00
Grégoire Paris
56e5856ad7 Remove dummy title
This was never meant to be under version control. Did not spot it in the
diff.

Closes #10836
2023-07-12 11:06:06 +02:00
Grégoire Paris
b5987ad29a Merge pull request #10598 from opsway/fix-generated-for-joined-inheritance
Support not Insertable/Updateable columns for entities with `JOINED` inheritance type
2023-07-11 23:48:10 +02:00
Grégoire Paris
385bdd33f1 Merge pull request #10798 from greg0ire/less-partial-load
Resort on Query::HINT_FORCE_PARTIAL_LOAD less
2023-07-11 23:46:17 +02:00
Nicolas Grekas
8c513a6523 Cleanup psalm-type AutogenerateMode (#10833) 2023-07-11 23:01:02 +02:00
Grégoire Paris
1413b496d7 Merge pull request #10824 from greg0ire/fix-build 2023-07-11 12:10:23 +02:00
Alexandr Vronskiy
3b3056f910 mistake on final property 2023-07-11 09:38:34 +03:00
Alexandr Vronskiy
fa5c37e972 Add final to protected
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-07-11 09:38:34 +03:00
Yevhen Vilkhovchenko
f3e36debfe Fix persist notInsertable|notUpdatable fields of root entity of joined inheritance type
1. Inherit ClassMetadataInfo::requiresFetchAfterChange flag from root entity when process parent columns mapping (see ClassMetadataInfo::addInheritedFieldMapping(), it uses same condition as ClassMetadataInfo::mapField()) so JoinedSubclassPersister::assignDefaultVersionAndUpsertableValues() to be called in JoinedSubclassPersister::executeInserts().
2. Override JoinedSubclassPersister::fetchVersionAndNotUpsertableValues() to fetch all parent tables (see $this->getJoinSql() call) generated columns. So make protected BasicEntityPersister::identifierFlattener stateless service (use it flattenIdentifier() method) and BasicEntityPersister::extractIdentifierTypes() (to avoid copy-paste).
3. JoinedSubclassPersister::fetchVersionAndNotUpsertableValues() doesnt check empty $columnNames because it would be an error if ClassMetadataInfo::requiresFetchAfterChange is true while no generated columns in inheritance hierarchy.
4. Initialize JoinedInheritanceRoot not-nullable string properties with insertable=false attribute to avoid attempt to insert default null data which cause error:
    PDOException: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "rootwritablecontent" of relation "joined_inheritance_root" violates not-null constraint
    DETAIL:  Failing row contains (5, null, dbDefault, dbDefault, , nonUpdatable).
  while $rootTableStmt->executeStatement() because JoinedSubclassPersister::getInsertColumnList() have no $insertData (prepared later) to decide is generated column provided by client code or not (so need to skip column)
2023-07-11 09:38:34 +03:00
Yevhen Vilkhovchenko
ca7abd04a2 Fix persist notInsertable|notUpdatable columns of entity with joined inheritance type
1. Postgres gives error when insert root entity ($rootTableStmt->executeStatement()) in JoinedSubclassPersister::executeInserts():
   PDOException: SQLSTATE[08P01]: <<Unknown error>>: 7 ERROR:  bind message supplies 4 parameters, but prepared statement "" requires 6
  so exclude notInsertable columns from JoinedSubclassPersister::getInsertColumnList() like it done in parent::prepareInsertData() which call BasicEntityPersister::prepareUpdateData(isInsert: true) where we have condition:
    if ($isInsert && isset($fieldMapping['notInsertable']))
2. Try to get generated (notInsertable|notUpdatable) column value on flush() with JoinedSubclassPersister::executeInserts() also fails:
    Unexpected empty result for database query.
  because method it calls $this->assignDefaultVersionAndUpsertableValues() after insert root entity row, while generated columns in child-entity table, so move call just after insert child row
3. Use option['default'] = 'dbDefault' in functional test entities, to emulate generated value on insert, but declare as generated = 'ALWAYS' for tests purpose (correctness of JoinedSubclassPersister::fetchVersionAndNotUpsertableValues() sql-query)
4. Use JoinedInheritanceRoot::rootField to skip JoinedSubclassPersister::update() optimization for empty changeset in updatable:false columns tests
2023-07-11 09:38:34 +03:00
Matthias Pigulla
a555626150 Improve and add test to set to-one and to-many associations with reference objects (#10799) 2023-07-11 00:07:02 +02:00
Grégoire Paris
ec7a8a7a0f Merge pull request #10828 from greg0ire/matching-xml
Match namespace in XML file with namespace in XSD file
2023-07-09 23:02:43 +02:00
Grégoire Paris
e94fa8588d Match namespace in XML file with namespace in XSD file
In 7fa3e6ec7c, a global search and replace
was used for http and https.
This broke the documentation examples in that as soon as you turn on XSD
validation, it will fail because the namespace in the XML file does not
match the ones defined in the XSD file, which do not exhibit the https.

Note that this is not a security concern, because these URIs are
not meant to be actually resolved, but to serve as a unique identifier
for the namespace in which we define our elements.
2023-07-09 21:18:57 +02:00
Matthias Pigulla
f26946b477 Add @deprecated annotations in addition to runtime deprecation notices 2023-07-08 16:22:55 +02:00
Matthias Pigulla
efc83bce8e Make it possible to have non-NULLable self-referencing associations when using application-provided IDs (#10735)
This change improves scheduling of extra updates in the `BasicEntityPersister`.

Extra updates can be avoided when
* the referred-to entity has already been inserted during the current insert batch/transaction
* we have a self-referencing entity with application-provided ID values (the `NONE` generator strategy).

As a corollary, with this change applications that provide their own IDs can define self-referencing associations as not NULLable.

I am considering this a bugfix since the ORM previously executed additional queries that were not strictly necessary, and that required users to work with NULLable columns where conceptually a non-NULLable column would be valid and more expressive.

One caveat, though:

In the absence of entity-level commit ordering (#10547), it is not guaranteed that entities with self-references (at the class level) will be inserted in a suitable order. The order depends on the sequence in which the entities were added with `persist()`.

Fixes #7877, closes #7882.

Co-authored-by: Sylvain Fabre <sylvain.fabre@assoconnect.com>
2023-07-08 15:53:54 +02:00
Grégoire Paris
450cae2caa Add dummy title to the sidebar before checking docs
The way we have our docs, the sidebar is a separate document and as
such, needs a title. Let us prepend a dummy title until the guides-cli
provides a way to ignore that particular error.
2023-07-07 13:59:27 +02:00
Grégoire Paris
81ddeb426c Merge pull request #10823 from nicolas-grekas/mergeup 2023-07-07 13:09:11 +02:00
Nicolas Grekas
42e63bf358 Merge branch 2.15.x into 2.16.x
* 2.15.x: (23 commits)
  Fix cloning entities when using lazy-ghost proxies
  Fixes recomputation of single entity change set when entity contains enum attributes. Due to the fact that originalEntityData contains enum objects and ReflectionEnumProperty::getValue() returns value of enum, comparison of values are always falsy, resulting to update columns value even though it has not changes.
  Fix code style issues
  Use absolute references
  Avoid colon followed by double colon
  Use correct syntax for references
  Fix invalid reference syntax
  Use rst syntax
  Use internal link
  Escape pipes
  Introduce new workflow to test docs
  Remove lone dash (#10812)
  Treat id field proprites same as regular field
  Move three "Ticket/"-style tests to the right namespace
  Follow recommendation about multiline type
  Fix unserialize() errors when running tests on PHP 8.3 (#10803)
  Explain `EntityManager::getReference()` peculiarities (#10800)
  Upgrade to Psalm 5.13
  test: assert `postLoad` has data first
  distinct() updates QueryBuilder state correctly
  ...
2023-07-07 12:55:31 +02:00
Grégoire Paris
4978e0e336 Merge pull request #10819 from nicolas-grekas/fix-proxy-clone 2023-07-06 16:23:53 +02:00
Nicolas Grekas
eee87c376d Fix cloning entities when using lazy-ghost proxies 2023-07-06 15:08:59 +02:00
Grégoire Paris
0b9060c728 Merge pull request #10806 from rmikalkenas/fix-enum-recomputation 2023-07-06 10:23:59 +02:00
Grégoire Paris
514f6b8c28 Merge pull request #10813 from Greg0/fix-primary-id-mapping-xml-driver 2023-07-06 09:12:53 +02:00
Rokas Mikalkėnas
c1018fe299 Fixes recomputation of single entity change set when entity contains enum attributes.
Due to the fact that originalEntityData contains enum objects and
ReflectionEnumProperty::getValue() returns value of enum,
comparison of values are always falsy, resulting to update
columns value even though it has not changes.
2023-07-05 23:57:34 +03:00
Grzegorz Kuźnik
075824f5b5 Fix code style issues 2023-07-05 21:10:48 +02:00
Grégoire Paris
d6f4834476 Merge pull request #10815 from greg0ire/test-docs 2023-07-05 10:01:37 +02:00
Grégoire Paris
9dadffe270 Use absolute references
According to the Sphinx docs, when in reference/architecture.rst, a
reference to reference/inheritance-mapping would resolve to
reference/reference/inheritance-mapping.rst, because it is relative to
the current document
2023-07-04 17:44:44 +02:00
Grégoire Paris
b6e7e6d723 Avoid colon followed by double colon
It seems to confuse the guides-cli, if it is even valid.
2023-07-04 17:31:05 +02:00
Grégoire Paris
710937d6f8 Use correct syntax for references
doc was used when it is clearly a ref, plus there was a leading
underscore preventing the resolution.
2023-07-04 17:26:04 +02:00
Grégoire Paris
5d2d6642c8 Fix invalid reference syntax
Without this change, a hash is displayed for some reason.
2023-07-04 17:14:03 +02:00
Grégoire Paris
4d56711d8c Use rst syntax
Using underscore for emphasis is not an RST thing, in rst the difference
between emphasis and strong emphasis is in the number of asterisks.

Right now these underscores are just ignored and displayed on the
website.

See https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#emphasis
2023-07-04 17:11:46 +02:00
Grégoire Paris
a157bc3fb3 Use internal link 2023-07-04 17:05:47 +02:00
Grégoire Paris
1aeab391c7 Escape pipes
Pipes can be used to define substitutions, it is part of the rst
standard. This explains why some of the links in this document are not
displayed on the website.

See https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-definitions
2023-07-04 16:48:14 +02:00
Grégoire Paris
a4ecd02349 Introduce new workflow to test docs
This allows to check compatibility with phpDocumentor/guides, but also
should allow to spot embarassing mistakes in our existing docs.
2023-07-04 16:45:18 +02:00
Matthias Pigulla
bb21865cba Deprecate classes related to old commit order computation 2023-07-04 14:30:29 +02:00
Matthias Pigulla
606da9280d Un-prefix simple generics like list<> and array<>
... as suggested in GH review.
2023-07-04 14:17:14 +02:00
Grégoire Paris
21708e43c4 Merge pull request #10785 from mpdude/guard-duplicate-identity-map-entries 2023-07-04 10:03:04 +02:00
Grégoire Paris
8c59828f6c Remove lone dash (#10812) 2023-07-03 21:46:12 +02:00
Grzegorz K
0877ecbe56 Treat id field proprites same as regular field 2023-07-03 15:15:08 +02:00
Grégoire Paris
8eb69922e6 Merge pull request #10809 from mpdude/show-trouble-delete-before-insert
Add test to show why delete-before-insert may be challenging
2023-06-30 08:08:57 +02:00
Matthias Pigulla
e9b6fd89a4 Add test to show why delete-before-insert may be challenging
There are a few requests (#5742, #5368, #5109, #6776) that ask to change the order of operations in the UnitOfWork to perform "deletes before inserts", or where such a switch appears to solve a reported problem.

I don't want to say that this is not doable. But this PR at least adds two tricky examples where INSERTs need to be done before an UPDATE can refer to new database rows; and where the UPDATE needs to happen to release foreign key references to other entities before those can be DELETEd.

So, at least as long as all operations of a certain type are to be executed in blocks, this example allows no other order of operations than the current one.
2023-06-29 14:32:08 +02:00
Matthias Pigulla
01a14327d2 Add a safeguard against multiple objects competing for the same identity map entry
While trying to understand #3037, I found that it may happen that we have more entries in `\Doctrine\ORM\UnitOfWork::$entityIdentifiers` than in `\Doctrine\ORM\UnitOfWork::$identityMap`.

The former is a mapping from `spl_object_id` values to ID hashes, the latter an array first of entity class names and then from ID hash to entity object instances.

(Basically, "ID hash" is a concatenation of all field values making up the `@Id` for a given entity.)

This means that at some point, we must have _different_ objects representing the same entity, or at least over time different objects are used for the same entity without the UoW properly updating its `::$entityIdentifiers` structure.

I don't think it makes sense to overwrite an entity in the identity map, since that means a currently `MANAGED` entity is replaced with something else.

If it makes sense at all to _replace_ an entity, that should happen through dedicated management methods to first detach the old entity before persisting, merging or otherwise adding the new one. This way we could make sure the internal structures remain consistent.
2023-06-28 22:50:17 +02:00
Grégoire Paris
4887359827 Merge pull request #10807 from mpdude/move-tests
Move three "Ticket/"-style tests to the right namespace
2023-06-28 20:54:43 +02:00
Matthias Pigulla
2df1071e7a Remove references to the temporary branch in workflow definitions 2023-06-28 17:10:20 +02:00
Matthias Pigulla
5afe9b80a8 Move three "Ticket/"-style tests to the right namespace 2023-06-28 16:39:47 +02:00
Matthias Pigulla
7fc359c2bb Avoid unnecessarily passing entity lists into executeDeletions/executeInserts 2023-06-28 14:46:22 +02:00
Matthias Pigulla
853b9f75ae Merge remote-tracking branch 'origin/2.16.x' into commit-order-entity-level 2023-06-28 14:43:54 +02:00
Grégoire Paris
584c4aeed1 Merge pull request #10804 from greg0ire/parenthesized 2023-06-28 14:11:41 +02:00
Grégoire Paris
44d2a83e09 Merge pull request #10532 from mpdude/entity-persister-must-not-batch 2023-06-28 11:45:39 +02:00
Grégoire Paris
c9c5157fda Follow recommendation about multiline type
Apparently, there is consensus about multiline types between:

- PHPStan
- Psalm
- Slevomat Coding Standard

See https://github.com/slevomat/coding-standard/issues/1586#issuecomment-1610195706

Using parenthesis is less ambiguous, it makes it clear to the parser
where the type begins and where it ends.

The change has a positive impact on the Psalm baseline, showing
that psalm-return annotation was not really understood previously.
2023-06-28 07:46:35 +02:00
Grégoire Paris
dba90c1a91 Merge pull request #10786 from vuongxuongminh/fix-attach-entity-listener-when-reset-class-metadata-factory
Fix attach entity listener when reset class metadata factory
2023-06-27 23:53:01 +02:00
Grégoire Paris
5f079c2061 Merge pull request #10531 from mpdude/commit-order-must-be-entity-level
Add test: Commit order calculation must happen on the entity level
2023-06-27 23:52:33 +02:00
Nicolas Grekas
55d477dc50 Fix unserialize() errors when running tests on PHP 8.3 (#10803) 2023-06-27 17:47:09 +02:00
Grégoire Paris
4da8d3be96 Resort on Query::HINT_FORCE_PARTIAL_LOAD less
A lot of our tests mention it, but I do not think it is important to the
test. Maybe it was a way to have more efficient tests? Most times,
removing the hint does not affect the test outcome.
2023-06-27 08:37:05 +02:00
Matthias Pigulla
4aadba65ce Explain EntityManager::getReference() peculiarities (#10800)
* Explain `EntityManager::getReference()` peculiarities

As one takeaway from https://github.com/doctrine/orm/issues/3037#issuecomment-1605657003 and #843, we should look into better explaining the `EntityManager::getReference()` method, it’s semantics, caveats and potential responsibilities placed on the user.

This PR tries to do that, so it fixes #10797.

* Update docs/en/reference/advanced-configuration.rst

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

---------

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-06-27 00:16:55 +02:00
Grégoire Paris
814d8d4d39 Merge pull request #10802 from greg0ire/psalm-5-13
Upgrade to Psalm 5.13
2023-06-27 00:05:00 +02:00
Grégoire Paris
dc411954ad Upgrade to Psalm 5.13
This is a nice release as far as the ORM is concerned:
- a small baseline reduction;
- lots of useless calls to sprintf spotted.
2023-06-26 19:12:02 +02:00
Minh Vuong
da29eb675c test: assert postLoad has data first 2023-06-26 09:29:00 +07:00
Grégoire Paris
b17e52ba6b Merge pull request #10791 from mpdude/understand-3037
Avoid creating unmanaged proxy instances for referred-to entities during `merge()`
2023-06-25 23:52:53 +02:00
Grégoire Paris
7ef4afc688 Merge pull request #10743 from mpdude/post-insert-id-early
Make EntityPersisters tell the UoW about post insert IDs early
2023-06-25 23:51:15 +02:00
Grégoire Paris
4e138903d0 Merge pull request #10789 from macroparts/distinct-updates-state-correctly
distinct() updates QueryBuilder state correctly
2023-06-25 18:11:37 +02:00
Daniel Jurkovic
efb50b9bdd distinct() updates QueryBuilder state correctly
Previously calling distinct() when the QueryBuilder was in clean state would cause subsequent getDQL() calls to ignore the distinct queryPart

Fixes #10784
2023-06-25 17:53:24 +02:00
Grégoire Paris
70bcff7410 Merge pull request #10794 from doctrine/2.15.x
Merge 2.15.x up into 2.16.x
2023-06-23 23:22:31 +02:00
Matthias Pigulla
1989531d4f Update tests/Doctrine/Tests/ORM/Functional/Ticket/GH7407Test.php
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-06-23 22:47:34 +02:00
Grégoire Paris
f778d8cf98 Merge pull request #10792 from greg0ire/entity-level-commit-order
Entity level commit order
2023-06-23 22:37:10 +02:00
Grégoire Paris
18b32ab9db Merge remote-tracking branch 'origin/2.15.x' into entity-level-commit-order 2023-06-23 22:21:53 +02:00
Matthias Pigulla
d738ecfcfe Avoid creating unmanaged proxy instances for referred-to entities during merge()
This PR tries to improve the situation/problem explained in #3037:

Under certain conditions – there may be multiple and not all are known/well-understood – we may get inconsistencies between the `\Doctrine\ORM\UnitOfWork::$entityIdentifiers` and `\Doctrine\ORM\UnitOfWork::$identityMap` arrays.

Since the `::$identityMap` is a plain array holding object references, objects contained in it cannot be garbage-collected.
`::$entityIdentifiers`, however, is indexed by `spl_object_id` values. When those objects are destructed and/or garbage-collected, the OID may be reused and reassigned to other objects later on.

When the OID re-assignment happens to be for another entity, the UoW may assume incorrect entity states and, for example, miss INSERT or UPDATE operations.

One cause for such inconsistencies is _replacing_ identity map entries with other object instances: This makes it possible that the old object becomes GC'd, while its OID is not cleaned up. Since that is not a use case we need to support (IMHO), #10785 is about adding a safeguard against it.

In this test shown here, the `merge()` operation is currently too eager in creating a proxy object for another referred-to entity. This proxy represents an entity already present in the identity map at that time, potentially leading to this problem later on.
2023-06-23 22:19:06 +02:00
Matthias Pigulla
aa3ff458c7 Add test: Commit order calculation must happen on the entity level
Add tests for entity insertion and deletion that require the commit order calculation to happen on the entity level. This demonstrates the necessity for the changes in #10547.

This PR contains two tests with carefully constructed entity relationships, where we have a non-nullable `parent` foreign key relationships between entities stored in the same table.

Class diagram:

```mermaid
classDiagram
    direction LR
    class A
    class B
    A --> B : parent
    B --|> A
```

Object graph:

```mermaid
graph LR;
    b1 --> b2;
    b2 --> a;
    b3 --> b2;
```

 #### Situation before #10547

The commit order is computed by looking at the associations at the _table_ (= _class_) level. Once the ordering of _tables_ has been found, entities being mapped to the same table will be processed in the order they were given to `persist()` or `remove()`.

That means only a particular ordering of `persist()` or `remove()` calls (see comment in the test) works:

For inserts, the order must be `$a, $b2, $b1, $b3` (or `... $b3, $b1`), for deletions `$b1, $b3, $b2, $a`.

 #### Situation with entity-level commit order computation (as in #10547)

The ORM computes the commit order by considering associations at the _entity_ level. It will be able to find a working order by itself.
2023-06-23 22:14:04 +02:00
Grégoire Paris
f76bab2b73 Merge pull request #10790 from greg0ire/slevomat-cs-upgrade
Work around slevomat/coding-standard issues
2023-06-23 22:13:30 +02:00
Grégoire Paris
0e06d6b67d Apply latest coding standard rules 2023-06-23 18:11:22 +02:00
Grégoire Paris
5114dcee0b Work around slevomat/coding-standard issues
I tweaked the code so that it would not fall victim to
https://github.com/slevomat/coding-standard/issues/1585 or
https://github.com/slevomat/coding-standard/issues/1586, thus fixing the
phpcs job without losing information or breaking other jobs.
2023-06-23 18:11:07 +02:00
Matthias Pigulla
8bc74c624a Make EntityPersisters tell the UoW about post insert IDs early
This refactoring does two things:

* We can avoid collecting the post insert IDs in a cumbersome array structure that will be returned by the EntityPersisters and processed by the UoW right after. Instead, use a more expressive API: Make the EntityPersisters tell the UoW about the IDs immediately.
* IDs will be available in inserted entities a tad sooner. That may help to resolve #10735, where we can use the IDs to skip extra updates.
2023-06-23 09:08:07 +02:00
Grégoire Paris
6c0a5ecbf9 Merge pull request #10787 from doctrine/2.15.x-merge-up-into-2.16.x_XV3tWpNu 2023-06-22 16:01:49 +02:00
Grégoire Paris
5f6501f842 Merge remote-tracking branch 'origin/2.15.x' into 2.15.x-merge-up-into-2.16.x_XV3tWpNu 2023-06-22 14:44:27 +02:00
Alexander Dmitryuk
4c3bd20801 Fix missing setFilterSchemaAssetsExpression in phpdoc (#10776) 2023-06-22 14:36:06 +02:00
Grégoire Paris
f2abf6143b Merge pull request #10763 from mpdude/defer-collection-entity-removals-to-post-commit 2023-06-22 14:35:20 +02:00
Minh Vuong
338deacb58 fix: attach entity listener when reset metadata factory 2023-06-22 17:02:24 +07:00
Grégoire Paris
829d5fbb9f Merge pull request #10780 from greg0ire/avoid-partial 2023-06-22 10:04:27 +02:00
Matthias Pigulla
d220494edc Improve documentation on exact behaviour of many-to-many deletion operations 2023-06-21 19:14:55 +02:00
Matthias Pigulla
c235901544 Move a check up (continue early) 2023-06-21 19:14:55 +02:00
Matthias Pigulla
ba089e551a Avoid unnecessary changes 2023-06-21 19:14:55 +02:00
Matthias Pigulla
ee0b3f214d Write tests more concisely 2023-06-21 19:14:55 +02:00
Matthias Pigulla
930fa831b2 Test expected query counts in ManyToManyBasicAssociationTest
When collection updates/join table cleanups do not happen through specialized Entity-/CollectionPersister methods but instead as "plain" updates, we may issue a lot more queries than expected.
2023-06-21 19:14:55 +02:00
Matthias Pigulla
98b404875f Defer removing removed entities from to-many collections until after transaction commit 2023-06-21 19:14:55 +02:00
Grégoire Paris
fcc5c106b4 Rely on partial objects less when in tests
Partial objects are deprecated. They were handy to make the generated
SQL more legible, but we should refrain from relying on them.
2023-06-18 18:20:29 +02:00
Grégoire Paris
5132f0deb0 Stop using $message argument
It brings nothing over what PHPUnit now natively does.
2023-06-18 18:16:29 +02:00
Grégoire Paris
fe8e313731 Merge pull request #10747 from wtfzdotnet/feature/fix-one-to-many-custom-id-orphan-removal 2023-06-16 10:07:29 +02:00
Grégoire Paris
41f704cd96 Merge pull request #10775 from doctrine/2.15.x
Merge 2.15.x up into 2.16.x
2023-06-13 20:10:31 +02:00
Grégoire Paris
1adb5c0c70 Merge pull request #10774 from greg0ire/document-dto-in-rsm 2023-06-12 13:52:10 +02:00
Grégoire Paris
e5174af669 Document how to produce DTOs with a result set mapping 2023-06-11 18:02:18 +02:00
Vaidas
c3106f9fe7 Restore document proxy state to uninitialized on load exception (#10645) 2023-06-09 08:54:22 +02:00
Alexander M. Turek
cbf45dd97e PHPStan 1.10.18, Psalm 5.12.0 (#10771) 2023-06-08 16:57:07 +02:00
Michael Roterman
3c0d140e52 OneToManyPersister does not take custom identifier types into account for orphan removal.
In my case a custom doctrine type of Uuid object is converted to string by simply casting it, resulting in a hex DELETE FROM x WHERE id = ? query,
whilst it should've been converted along the way to it's binary representation. This leads to no deletions being made at all as you would expect making use of doctrine custom type's as an identifier.

This commit fixes usage of ramsey/uuid or symfony/uid as custom id types when making use of orphan removal.
2023-06-06 19:51:41 +02:00
Michael Roterman
33675ff4a9 fix: Update baseline and assertions for OneToManyPersister 2023-06-06 18:18:26 +02:00
Alexander M. Turek
5c74795893 Merge 2.15.x into 2.16.x (#10765) 2023-06-06 11:30:27 +02:00
Nicolas Grekas
3827dd769e Don't call deprecated getSQLResultCasing and usesSequenceEmulatedIdentityColumns when we know the platform (#10759) 2023-06-06 11:27:31 +02:00
Nicolas Grekas
6c9b29f237 Don't call canEmulateSchemas in SchemaTool when possible (#10762) 2023-06-05 21:42:13 +02:00
Grégoire Paris
2afe2dc8af Merge pull request #10758 from Gwemox/partial-revert-enum-id-hash 2023-06-05 11:41:32 +02:00
Thibault Buathier
cc3d872b95 revert: transform backed enum to value 2023-06-05 10:58:32 +02:00
Grégoire Paris
8961bfe90c Merge pull request #10756 from doctrine/2.15.x
Merge 2.15.x up into 2.16.x
2023-06-05 09:11:52 +02:00
Grégoire Paris
15e3a7e861 Merge pull request #10751 from mpdude/7180-fixed
Add test to show #7180 has been fixed
2023-06-05 08:35:40 +02:00
Grégoire Paris
65dc154ce5 Merge pull request #10754 from greg0ire/fix-build
Fix build
2023-06-05 08:35:26 +02:00
Grégoire Paris
1280e005b6 Merge pull request #10755 from mpdude/9192-fixed
Add test to show #9192 has been fixed
2023-06-04 22:08:17 +02:00
Matthias Pigulla
79f53d5dae Add test to show #9192 has been fixed
This test implements the situation described in #9192. The commit order computation will be fixed by #10547.
2023-06-04 19:46:16 +00:00
Grégoire Paris
caaa0d6192 Ignore error about get_class($metadata)
This is the result of the contradiction between the phpdoc
(ClassMetadata), and the condition, which guarantees $metadata is not a
ClassMetadata. Relaxing the phpdoc leads to other phpstan issues, about
properties that exist in ClassMetadata but not in
PersistentClassMetadata. The right way to fix this would be to switch
from a deprecation to an exception, but that is not the path we have
taken, and all this will disappear in 3.0.x anyway, so let's not bother.
2023-06-03 20:59:29 +02:00
Grégoire Paris
68d3a63957 Use class name directly
Static analysis points out $this->getName() may return null. But there
is worse: the message mentions a "command class", and getName() is not a
class.
2023-06-03 20:59:29 +02:00
Matthias Pigulla
bf2937e63a Add test: Entity insertions must not happen table-wise
Add tests for entity insertion and deletion that require writes to different tables in an interleaved fashion, and that have to re-visit a particular table.

 #### Background

In #10531, I've given an example where it is necessary to compute the commit order on the entity (instead of table) level.

Taking a closer look at the UoW to see how this could be achieved, I noticed that the current, table-level commit order manifests itself also in the API between the UoW and `EntityPersister`s.

 #### Current situation

The UoW computes the commit order on the table level. All entity insertions for a particular table are passed through `EntityPersister::addInsert()` and finally written through `EntityPersister::executeInserts()`.

 #### Suggested change

The test in this PR contains a carefully constructed set of four entities. Two of them are of the same class (are written to the same table), but require other entities to be processed first.

In order to be able to insert this set of entities, the ORM must be able to perform inserts for a given table repeatedly, interleaved with writing other entities to their respective tables.
2023-06-03 13:07:41 +00:00
Matthias Pigulla
76b8a215c2 Update docs that name in @Index/@UniqueConstraint is optional (#10748)
Fixes #4283.
2023-06-03 00:14:43 +02:00
Matthias Pigulla
b163cea61c Update the FAQ entry on setting MySQL charset and collation for columns (#10746)
Fixes #2986.
2023-06-03 00:13:07 +02:00
Grégoire Paris
ed212ab924 Merge pull request #10749 from mpdude/6499-fixed
Add tests to show #6499 has been fixed
2023-06-02 23:36:44 +02:00
Matthias Pigulla
dd0e02e912 Add test to show #7180 has been fixed
Tests suggested in https://github.com/doctrine/orm/pull/7180#issuecomment-380841413 and https://github.com/doctrine/orm/pull/7180#issuecomment-381067448 by @arnaud-lb.

Co-authored-by: Arnaud Le Blanc <arnaud.lb@gmail.com>
2023-06-02 21:28:11 +00:00
Matthias Pigulla
aad875eea1 Add tests to show #6499 has been fixed
@frikkle was the first to propose these tests in #6533.
@rvanlaak followed up in #8703, making some adjustments.

Co-authored-by: Gabe van der Weijde <gabe.vanderweijde@triasinformatica.nl>
Co-authored-by: Richard van Laak <rvanlaak@gmail.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-06-02 21:14:17 +00:00
Grégoire Paris
84ab535e56 Merge pull request #10750 from mpdude/7006-fixed
Add test to show #7006 has been fixed
2023-06-02 22:07:47 +02:00
Matthias Pigulla
a72a0c3597 Update tests/Doctrine/Tests/ORM/Functional/Ticket/GH7006Test.php
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-06-02 22:00:20 +02:00
Matthias Pigulla
6217285544 Add test to show #7006 has been fixed 2023-06-02 17:52:51 +00:00
Grégoire Paris
330c0bc67e Merge pull request #10689 from mpdude/insert-entity-level-topo-sort 2023-06-02 15:21:08 +02:00
Grégoire Paris
b5595ca041 Merge pull request #10732 from mpdude/10348-fixed
Add a test case to show #10348 has been fixed
2023-06-02 07:50:03 +02:00
Grégoire Paris
4dfbe13897 Merge pull request #10740 from greg0ire/remove-ignore-rule
Remove useless ignore rule
2023-06-02 00:14:27 +02:00
Grégoire Paris
b64e1c9b1f Remove useless ignore rule
This is useless since 152f91fa3
2023-06-01 21:03:58 +02:00
Grégoire Paris
b779b112f3 Merge pull request #10738 from doctrine/2.15.x-merge-up-into-2.16.x_PvK1bbO1 2023-06-01 11:45:08 +02:00
Grégoire Paris
bf449bef7d Merge pull request #10737 from nicolas-grekas/lexer-deprec 2023-06-01 11:35:50 +02:00
Nicolas Grekas
152f91fa33 Fix deprecations from doctrine/lexer 2023-06-01 11:22:36 +02:00
Grégoire Paris
14d1eb5340 Document pdo_sqlite requirement for tests (#10734) 2023-06-01 08:57:07 +02:00
Matthias Pigulla
04e08640fb Add a test case to show #10348 has been fixed by #10566
This is part of the series of issues fixed by #10547. In particular, the changes from #10566 were relevant.

See #10348 for the bug description.

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-05-31 21:38:42 +00:00
Matthias Pigulla
aa27b3a35f Remove the now unused UnitOfWork::getCommitOrder() method 2023-05-31 07:31:56 +00:00
Matthias Pigulla
d76fc4ebf6 Compute entity-level commit order for entity insertions
This is the third step to break https://github.com/doctrine/orm/pull/10547 into smaller PRs suitable for reviewing. It uses the new topological sort implementation from #10592 and the refactoring from #10651 to compute the UoW's commit order for entity insertions not on the entity class level, but for single entities and their actual dependencies instead.

 #### Current situation

`UnitOfWork::getCommitOrder()` would compute the entity sequence on the class level with the following code:

70477d81e9/lib/Doctrine/ORM/UnitOfWork.php (L1310-L1325)

 #### Suggested change

* Instead of considering the classes of all entities that need to be inserted, updated or deleted, consider the new (inserted) entities only. We only need to find a sequence in situations where there are foreign key relationships between two _new_ entities.
* In the dependency graph, add edges for all to-one association target entities.
* Make edges "optional" when the association is nullable.

 #### Test changes

I have not tried to fully understand the few changes necessary to fix the tests. My guess is that those are edge cases where the insert order changed and we need to consider this during clean-up.

Keep in mind that many of the functional tests we have assume that entities have IDs assigned in the order that they were added to the EntityManager. That does not change – so the order of entities is generally stable, equal to the previous implementation.
2023-05-31 07:16:16 +00:00
Grégoire Paris
da0998c401 Add missing underscore to RST links (#10731) 2023-05-30 23:00:28 +02:00
Matthias Pigulla
ae60cf005f Commit order for removals has to consider SET NULL, not nullable (#10566)
When computing the commit order for entity removals, we have to look out for `@ORM\JoinColumn(onDelete="SET NULL")` to find places where cyclic associations can be broken.

 #### Background

The UoW computes a "commit order" to find the sequence in which tables shall be processed when inserting entities into the database or performing delete operations.

For the insert case, the ORM is able to schedule _extra updates_ that will be performed after all entities have been inserted. Associations which are configured as `@ORM\JoinColumn(nullable=true, ...)` can be left as `NULL` in the database when performing the initial `INSERT` statements, and will be updated once all new entities have been written to the database. This can be used to break cyclic associations between entity instances.

For removals, the ORM does not currently implement up-front `UPDATE` statements to `NULL` out associations before `DELETE` statements are executed. That means when associations form a cycle, users have to configure `@ORM\JoinColumn(onDelete="SET NULL", ...)` on one of the associations involved. This transfers responsibility to the DBMS to break the cycle at that place.

_But_, we still have to perform the delete statements in an order that makes this happen early enough. This may be a _different_ order than the one required for the insert case. We can find it _only_ by looking at the `onDelete` behaviour. We must ignore the `nullable` property, which is irrelevant, since we do not even try to `NULL` anything.

 #### Example

Assume three entity classes `A`, `B`, `C`. There are unidirectional one-to-one associations `A -> B`, `B -> C`, `C -> A`. All those associations are `nullable= true`.

Three entities `$a`, `$b`, `$c` are created from these respective classes and associations are set up.

All operations `cascade` at the ORM level. So we can test what happens when we start the operations at the three individual entities, but in the end, they will always involve all three of them.

_Any_ insert order will work, so the improvements necessary to solve #10531 or #10532 are not needed here. Since all associations are between different tables, the current table-level computation is good enough.

For the removal case, only the `A -> B` association has `onDelete="SET NULL"`. So, the only possible execution order is `$b`, `$c`, `$a`. We have to find that regardless of where we start the cascade operation.

The DBMS will set the `A -> B` association on `$a` to `NULL` when we remove `$b`. We can then remove `$c` since it is no longer being referred to, then `$a`.

 #### Related cases

These cases ask for the ORM to perform the extra update before the delete by itself, without DBMS-level support:
* #5665
* #10548
2023-05-30 22:58:36 +02:00
Alexander M. Turek
ddd3066bc4 Revert "Allow symfony/console 7 (#10724)"
This reverts commit 6662195936.
2023-05-25 08:48:53 +02:00
Alexander M. Turek
6662195936 Allow symfony/console 7 (#10724) 2023-05-25 08:47:35 +02:00
Grégoire Paris
cc011d8215 Merge pull request #10725 from doctrine/2.14.x
Merge 2.14.x up into 2.15.x
2023-05-24 14:08:21 +02:00
Grégoire Paris
d831c126c9 Merge pull request #10643 from htto/bugfix/sti-with-abstract-intermediate
Fix single table inheritance with intermediate abstract class(es)
2023-05-24 11:58:11 +02:00
Grégoire Paris
10eae1a7ff Merge pull request #10722 from phansys/query_single_result_exception
Fix and improve functional test cases expecting `NonUniqueResultException` from `AbstractQuery::getSingleScalarResult()`
2023-05-23 22:46:18 +02:00
Grégoire Paris
d951aa05b9 Merge pull request #10721 from phansys/query_single_result 2023-05-23 11:33:49 +02:00
Javier Spagnoletti
be297b9fd3 Narrow return types for AbstractQuery::getSingleScalarResult() 2023-05-23 05:47:39 -03:00
Javier Spagnoletti
125e18cf24 Fix and improve functional test cases expecting NonUniqueResultException from AbstractQuery::getSingleScalarResult() 2023-05-23 05:32:38 -03:00
Grégoire Paris
8fba9d6868 Merge pull request #10708 from mbabker/2.15-link-fix 2023-05-16 17:06:17 +02:00
Michael Babker
7f4f1cda71 Correct docs link 2023-05-16 09:38:09 -05:00
Grégoire Paris
4e137f77a5 Merge pull request #10704 from greg0ire/drop-useless-block
Remove unreachable piece of code
2023-05-16 08:19:42 +02:00
Grégoire Paris
a33aa15c79 Remove unreachable piece of code
mappedBy is never defined on an inverse relationship.
Bi-directional self-referencing should IMO still result in 2 separate
associations, on 2 separate fields of the same class, like mentor or
mentee.
2023-05-15 14:10:22 +02:00
Grégoire Paris
255ce51526 Merge pull request #10703 from doctrine/2.15.x 2023-05-15 12:05:48 +02:00
Grégoire Paris
1c905b0e0a Merge pull request #10702 from greg0ire/fix-build 2023-05-15 11:53:09 +02:00
Grégoire Paris
7901790b97 Adapt to latest coding standards 2023-05-15 11:42:13 +02:00
Grégoire Paris
cef1d2d740 Merge pull request #10666 from MatTheCat/inherited-readonly-properties
Create `ReflectionReadonlyProperty` from their declaring class so their value can be set
2023-05-12 07:50:03 +02:00
Grégoire Paris
8126882305 Merge pull request #10486 from mpdude/fix-to-many-update-on-delete
Fix to-many collections left in dirty state after entities are removed by the UoW
2023-05-12 00:11:56 +02:00
Matthias Pigulla
a9513692cb Fix to-many collections left in dirty state after entities are removed by the UoW 2023-05-12 00:02:44 +02:00
Grégoire Paris
52c3d9d82a Merge pull request #10508 from Gwemox/fix-enum-identity
Fix id hash of entity with enum as identifier
2023-05-12 00:00:20 +02:00
MatTheCat
2f46e5a130 Rename test class and method 2023-05-11 09:36:43 +02:00
Mathieu
a3fa1d7faa Replace assertions by @doesNotPerformAssertions 2023-05-11 09:33:12 +02:00
MatTheCat
c7c57be0c2 Create ReflectionReadonlyProperty from their declaring class so their value can be set 2023-05-11 09:33:12 +02:00
MatTheCat
721794fb9c Add test case 2023-05-11 09:33:12 +02:00
Grégoire Paris
38e47fdeab Merge pull request #10455 from mpdude/fix-mapping-driver-load
Make Annotations/Attribute mapping drivers report fields for the classes where they are declared
2023-05-08 15:46:54 +02:00
Matthias Pigulla
9ac063d879 Add a new topological sort implementation (#10592)
This is the first chunk to break #10547 into smaller PRs suitable for reviewing. It adds a new topological sort implementation.

 #### Background

Topological sort is an algorithm that sorts the vertices of a directed acyclic graph (DAG) in a linear order such that for every directed edge from vertex A to vertex B, vertex A comes before vertex B in the ordering. This ordering is called a topological order.

Ultimately (beyond the scope of this PR), in the ORM we'll need this to find an order in which we can insert new entities into the database. When one entity needs to refer to another one by means of a foreign key, the referred-to entity must be inserted before the referring entity. Deleting entities is similar.

A topological sorting can be obtained by running a depth first search (DFS) on the graph. The order in which the DFS finishes on the vertices is a topological order. The DFS is possible iif there are no cycles in the graph. When there are cycles, the DFS will find them.

For more information about topological sorting, as well as a description of an DFS-based topological sorting algorithm, see https://en.wikipedia.org/wiki/Topological_sorting.

 #### Current situation

There is a DFS-based topological sorting implemented in the `CommitOrderCalculator`. This implementation has two kinks:

1. It does not detect cycles

When there is a cycle in the DAG that cannot be resolved, we need to know about it. Ultimately, this means we will not be able to insert entities into the database in any order that allows all foreign keys constraints to be satisfied.

If you look at `CommitOrderCalculator`, you'll see that there is no code dealing with this situation.

2. It has an obscure concept of edge "weights"

To me, it is not clear how those are supposed to work. The weights are related to whether a foreign key is nullable or not, but can (could) be arbitrary integers. An edge will be ignored if it has a higher (lower) weight than another, already processed edge... 🤷🏻?

 #### Suggested change

In fact, when inserting entities into the database, we have two kinds of foreign key relationships: Those that are `nullable`, and those that are not.

Non-nullable foreign keys are hard requirements: Referred-to entities must be inserted first, no matter what. These are "non-optional" edges in the dependency graph.

Nullable foreign keys can be set to `NULL` when first inserting an entity, and then coming back and updating the foreign key value after the referred-to (related) entity has been inserted into the database. This is already implemented in `\Doctrine\ORM\UnitOfWork::scheduleExtraUpdate`, at the expense of performing one extra `UPDATE` query after all the `INSERT`s have been processed. These edges are "optional".

When finding a cycle that consists of non-optional edges only, treat it as a failure. We won't be able to insert entities with a circular dependency when all foreign keys are non-NULLable.

When a cycle contains at least one optional edge, we can use it to break the cycle: Use backtracking to go back to the point before traversing the last _optional_ edge. This omits the edge from the topological sort order, but will cost one extra UPDATE later on.

To make the transition easier, the new implementation is provided as a separate class, which is marked as `@internal`.

 #### Outlook

Backtracking to the last optional edge is the simplest solution for now. In general, it might be better to find _another_ (optional) edge that would also break the cycle, if that edge is also part of _other_ cycles.

Remember, every optional edge skipped costs an extra UPDATE query later on. The underlying problem is known as the "minimum feedback arc set" problem, and is not easily/efficiently solvable. Thus, for the time being, picking the nearest optional edge seems to be reasonable.
2023-05-08 13:30:07 +02:00
Matthias Pigulla
b52a8f8b9e Make Annotations/Attribute mapping drivers report fields for the classes where they are declared
This PR will make the annotations and attribute mapping drivers report mapping configuration for the classes where it is declared, instead of omitting it and reporting it for subclasses only. This is necessary to be able to catch mis-configurations in `ClassMetadataFactory`.

Fixes #10417, closes #10450, closes #10454.

#### ⚠️ Summary for users getting `MappingExceptions` with the new mode

When you set the `$reportFieldsWhereDeclared` constructor parameters to `true` for the AnnotationDriver and/or AttributesDriver and get `MappingExceptions`, you may be doing one of the following:

* Using `private` fields with the same name in different classes of an entity inheritance hierarchy (see #10450)
* Redeclaring/overwriting mapped properties inherited from mapped superclasses and/or other entities (see #10454)

As explained in these two PRs, the ORM cannot (or at least, was not designed to) support such configurations. Unfortunately, due to the old – now deprecated – driver behaviour, the misconfigurations could not be detected, and due to previously missing tests, this in turn was not noticed.

#### Current situation

The annotations mapping driver has the following condition to skip properties that are reported by the PHP reflection API:

69c7791ba2/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php (L345-L357)

This code has been there basically unchanged since the initial 2.0 release. The same condition can be found in the attribute driver, probably it has been copied when attributes were added.

I _think_ what the driver tries to do here is to deal with the fact that Reflection will also report `public`/`protected` properties inherited from parent classes. This is supported by the observation (see #5744) that e. g. YAML and XML drivers do not contain this logic.

The conditions are not precise enough for edge cases. They lead to some fields and configuration values not even being reported by the driver. 

Only since the fields would be "discovered" again when reflecting on subclasses, they eventually end up in class metadata structures for the subclasses. In one case of inherited ID generator mappings, the `ClassMetadataFactory` would also rely on this behaviour.

Two potential bugs that can result from this are demonstrated in #10450 and #10454.

#### Suggested solution

In order to find a more reliable way of separating properties that are merely reported again in subclasses from those that are actual re-declarations, use the information already available in `ClassMetadata`. In particular, `declared` tells us in which non-transient class a "field" was first seen.

Make the mapping driver skip only those properties for which we already know that they have been declared in parent classes, and skip them only when the observed declaring class matches the expectation. 

For all other properties, report them to `ClassMetadataFactory` and let that deal with consistency checking/error handling.

#10450 and #10454 are merged into this PR to show that they pass now.

#### Soft deprecation strategy

To avoid throwing new/surprising exceptions (even for misconfigurations) during a minor version upgrade, the new driver mode is opt-in.

Users will have to set the `$reportFieldsWhereDeclared` constructor parameters to `true` for the `AnnotationDriver` and/or `AttributesDriver`. Unless they do so, a deprecation warning will be raised.

In 3.0, the "new" mode will become the default. The constructor parameter can be deprecated (as of ORM 3.1, probably) and is a no-op.

We need to follow up in other places (DoctrineBundle, ... – what else?) to make this driver parameter an easy-to-change configuration setting.
2023-05-08 11:23:28 +00:00
Terence Eden
70477d81e9 Documentation typo (#10686)
The past tense of spin is spun, not "spinned"

https://en.wiktionary.org/wiki/spin#English
2023-05-08 12:22:09 +02:00
Grégoire Paris
1b2771f964 Merge pull request #10685 from doctrine/2.15.x-merge-up-into-2.16.x_vNvlgHpG
Merge release 2.15.1 into 2.16.x
2023-05-07 21:06:56 +02:00
Alexander M. Turek
9bc6f5b4ac Support unserializing 2.14 ParserResult instances (#10684) 2023-05-07 20:56:25 +02:00
Grégoire Paris
9766b6b03e Merge pull request #10651 from mpdude/unit-of-work-schedule-single-entities
Prepare entity-level commit order computation in the `UnitOfWork`
2023-05-05 20:43:23 +02:00
Grégoire Paris
37c8953015 Merge pull request #10678 from doctrine/2.15.x
Merge 2.15.x up into 2.16.x
2023-05-05 08:25:43 +02:00
Grégoire Paris
60c625be17 Upgrade to Psalm 5.11.0 (#10679) 2023-05-05 07:21:05 +02:00
Grégoire Paris
8b0d6a13c2 Merge pull request #10671 from BoShurik/fix-attribute-many-to-many-mapping
Fix attribute ManyToMany mapping
2023-05-04 23:52:47 +02:00
Grégoire Paris
a7ac6ff8d9 Merge pull request #10677 from greg0ire/psalm-5-10
Upgrade to Psalm 5.10.0
2023-05-04 23:49:02 +02:00
Grégoire Paris
222d544b0c Upgrade to Psalm 5.10.0 2023-05-04 22:12:31 +02:00
Grégoire Paris
a199ca3002 Merge pull request #10676 from doctrine/2.15.x
Merge 2.15.x up into 2.16.x
2023-05-04 19:35:13 +02:00
ixitheblue
6f1fd7a81e Fix iteration index initialisation (#10675)
In the code examples of the use of the ``Query#toIterable()`` method, an index ``$i`` is used to control the size of the current batch, which ends when the condition ``($i % $batchSize) === 0`` becomes true.

Because this condition is preceded by ``++$i`` and ``$i`` is initialized to 1, the first batch is actually of size ``$batchSize - 1`` instead of ``$batchSize``.

To solve this, ``$i`` should be initialized to 0 instead of 1.
2023-05-04 14:43:56 +02:00
BoShurik
2af6e4db38 Take into account join columns specifications.
Currently, the AttributeDriver ignores any join column attribute specified on a many to many relationship.
Let's copy code from the AnnotationDriver to fix that.

Fixes #9902
2023-05-04 15:36:29 +03:00
BoShurik
b48dafded8 Update doc-block for AttributeDriverTest's fixtures 2023-05-04 15:35:40 +03:00
Grégoire Paris
ffe1550a68 Bump version numbers in the README (#10674)
2.15.0 has been released.
2023-05-04 13:44:58 +02:00
Grégoire Paris
eef5a1db81 Merge pull request #10668 from stollr/doc_attr_uniqueconstraint
Added doc for the fields parameter of the UniqueConstraint attribute
2023-05-04 08:13:33 +02:00
Grégoire Paris
c2d053d185 Update branch metadata (#10672) 2023-05-03 22:41:13 +02:00
stollr
77822d623e Added doc for the fields parameter of the UniqueConstraint attribute 2023-05-03 10:45:07 +02:00
Grégoire Paris
7b5fafffbe Merge pull request #10654 from mpdude/join-column-does-not-make-it-own
Deprecate usage of `@JoinColumn` on the inverse side of one-to-one associations
2023-04-26 20:52:02 +02:00
Matthias Pigulla
aba8d74017 Deprecate usage of @JoinColumn on the inverse side of one-to-one associations
Following up on #10652:

 #### Current situation

The implementation of `\Doctrine\ORM\Mapping\ClassMetadataInfo::_validateAndCompleteOneToOneMapping` will consider a field with a one-to-one association to be the owning side also when it configures `@JoinColumn` settings.

 #### Suggested change

For a one to one association, a field should be the inverse side when it uses the `mappedBy` attribute, and be the owning side otherwise. The `JoinColumn` may be configured on the owning side only.

This PR adds a deprecation notice when `@JoinColumn` is used on the side of a one-to-one association where `mappedBy` occurs.

In 3.0, this will throw a `MappingException`.
2023-04-25 15:29:17 +02:00
Alexander M. Turek
a056552db9 Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  PHPStan 1.10.14 (#10655)
  Remove JoinColumn from inverse side (#10652)
  Apply `SlevomatCodingStandard.Commenting.AnnotationName` CS rule (#10653)
2023-04-25 13:43:39 +02:00
Alexander M. Turek
1142a396d3 PHPStan 1.10.14 (#10655) 2023-04-25 13:32:39 +02:00
Grégoire Paris
f01b7d254d Remove JoinColumn from inverse side (#10652)
This makes no sense because it describes a one-to-one where each table
references the other one. I do not think this is deliberately supported,
and it probably will not be supported at all in 3.0.
2023-04-25 13:16:20 +02:00
Matthias Pigulla
ed34327941 More precisely state conditions for the postPersist event 2023-04-25 09:48:41 +02:00
Javier Spagnoletti
1ea8424e07 Apply SlevomatCodingStandard.Commenting.AnnotationName CS rule (#10653) 2023-04-25 08:56:58 +02:00
Matthias Pigulla
b42cf99402 Prepare entity-level commit order computation in the UnitOfWork
This is the second chunk to break #10547 into smaller PRs suitable for reviewing. It prepares the `UnitOfWork` to work with a commit order computed on the entity level, as opposed to a class-based ordering as before.

#### Background

#10531 and #10532 show that it is not always possible to run `UnitOfWork::commit()` with a commit order given in terms of  entity _classes_. Instead it is necessary to process entities in an order computed on the _object_ level. That may include

* a particular order for multiple entities of the _same_ class
* a particular order for entities of _different_ classes, possibly even going back and forth (entity `$a1` of class `A`, then `$b` of class `B`, then `$a2` of class `A` – revisiting that class).

This PR is about preparing the `UnitOfWork` so that its methods will be able to perform inserts and deletions on that level of granularity. Subsequent PRs will deal with implementing that particular order computation.

#### Suggested change

Change the private `executeInserts` and `executeDeletions` methods so that they do not take a `ClassMetadata` identifying the class of entities that shall be processed, but pass them the list of entities directly.

The lists of entities are built in two dedicated methods. That happens basically as previously, by iterating over `$this->entityInsertions` or `$this->entityDeletions` and filtering those by class.

#### Potential (BC breaking?) changes that need review scrutiny

* `\Doctrine\ORM\Persisters\Entity\EntityPersister::addInsert()` was previously called multiple times, before the insert would be performed by a call to `\Doctrine\ORM\Persisters\Entity\EntityPersister::executeInserts()`. With the changes here, this batching effectively no longer takes place. `executeInserts()` will always see one entity/insert only, and there may be multiple `executeInserts()` calls during a single `UoW::commit()` phase.
* The caching in `\Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister` previously would cache entities from the last executed insert batch only. Now it will collect entities across multiple batches. I don't know if that poses a problem.
* Overhead in `\Doctrine\ORM\Persisters\Entity\BasicEntityPersister::executeInserts` is incurred multiple times; that may, however, only be about SQL statement preparation and might be salvageable.
* The `postPersist` event previously was not dispatched before _all_ instances of a particular entity class had been written to the database. Now, it will be dispatched immediately after every single entity that has been inserted.
2023-04-24 13:32:09 +02:00
Grégoire Paris
ba9f51a363 Merge pull request #10648 from doctrine/2.14.x-merge-up-into-2.15.x_VZV5I0St
Merge release 2.14.3 into 2.15.x
2023-04-22 15:45:17 +02:00
Heiko Przybyl
1ae74b8ec5 Fix single table inheritance with intermediate abstract class(es)
Fixes #10625
2023-04-20 15:37:42 +02:00
Grégoire Paris
a64f315dfe Merge pull request #10642 from yobrx/patch-1 2023-04-20 11:46:32 +02:00
Yoann B
6ca319a6f4 fix array association on partial index 2023-04-20 10:59:39 +02:00
Grégoire Paris
fceb279947 Merge pull request #10630 from monadial/fix/fqcn-type-in-xml-mapping
Fixed xsd schema for support FQCN type
2023-04-16 10:26:37 +02:00
Alexander M. Turek
2977933119 Run tests on SQLite with foreign keys enabled (#10632) 2023-04-15 10:54:31 +02:00
Tomas Mihalicka
5ac6fadf29 Fixed xsd schema for support FQCN type
After update to orm 2.14.2 invalid xsd schema error is occured, when in field,id or attribute-override have type is FQCN
2023-04-14 18:16:35 +02:00
Grégoire Paris
e59ed88251 Merge pull request #10620 from ecourtial/fix-doc-typo
fix typo in HydrationCompleteHandler doc
2023-04-12 21:21:42 +02:00
Eric COURTIAL
a16aeaeac8 fix typo in HydrationCompleteHandler doc 2023-04-12 21:02:36 +02:00
Mathieu
fca1ef78a7 Handle null comparisons in ManyToManyPersister (#10587)
* Add test case for https://github.com/doctrine/orm/issues/7717

* Do not hide null equality checks in `SqlValueVisitor::walkComparison`

* Annotate `GH7717Parent::$children` type
2023-04-12 17:31:38 +02:00
Grégoire Paris
a78e5bcf65 Merge pull request #10519 from mpdude/deprecate-override-association
Deprecate overriding associations not inherited from a mapped superclass
2023-04-07 20:03:39 +02:00
Thibault Buathier
09b4a75ed3 Fix id hash of entity with enum as identifier
When an entity have a backed enum as identifier, `UnitOfWork` tries to
cast to string when generating the hash of the id.
This fix calls `->value` when identifier is a `BackedEnum`.
Fixes #10471
Fixes #10334
2023-04-03 17:20:48 +02:00
Grégoire Paris
b984b567b8 Merge pull request #10599 from amina-seraoui/2.14.x
fix(persistent-collection): check association is not nullable before using it as an array
2023-04-02 23:26:11 +02:00
tasmim-concept
92c56164ee throw exception if association is null 2023-04-01 08:50:06 +02:00
Grégoire Paris
b2707509fc Merge pull request #10605 from greg0ire/2.15.x
Merge 2.14.x up into 2.15.x
2023-03-30 20:37:50 +02:00
Grégoire Paris
1d02139d2a Merge remote-tracking branch 'origin/2.14.x' into 2.15.x 2023-03-30 17:22:56 +02:00
Grégoire Paris
e5fb1a4a8f Merge pull request #10604 from greg0ire/psalm-5.9.0 2023-03-30 17:18:54 +02:00
Grégoire Paris
8cb7a5e212 Upgrade to Psalm 5.9.0
It looks like some issues are now represented by different classes.
2023-03-30 17:05:25 +02:00
Grégoire Paris
7ed28dba50 Merge pull request #10601 from JanTvrdik/discriminated-column-options 2023-03-30 13:31:59 +02:00
Jan Tvrdík
f215515bab Support options like charset and collation on DiscriminatedColumn
[closes #10462]
2023-03-30 11:58:29 +02:00
Grégoire Paris
ffbfbfcda1 Merge pull request #10602 from greg0ire/remove-or
Remove duplicate array shape
2023-03-29 23:30:10 +02:00
Grégoire Paris
4a30f622ec Remove duplicate array shape
DiscriminatorColumnMapping is just a specialization of the array shape
that is right of the pipe: it has the same fields, except fewer fields
are nullable. The union of that is the same thing as the array shape.
2023-03-29 21:58:36 +02:00
Grégoire Paris
aec3556502 Merge pull request #10554 from mpdude/mapped-superclass-resolve-to-many-lazy-check
Make "targetEntity must not be a mapped superclass" a lazy check
2023-03-24 08:27:38 +01:00
Grégoire Paris
33a19f1bf3 Merge pull request #10593 from mpdude/workflows
Run workflows also for the `entity-level-commit-order` branch
2023-03-23 09:15:33 +01:00
Matthias Pigulla
b6669746b7 Run workflows also for the entity-level-commit-order branch 2023-03-23 08:01:15 +00:00
Grégoire Paris
da9b9de590 Merge pull request #10589 from e2palmes/patch-1 2023-03-22 12:12:27 +01:00
Emmanuel DE PALMÈS
9ec697db7d Added missing ';'
missing ';' on Obtaining the EntityManager section, bootstrap code line 32
2023-03-22 11:52:36 +01:00
Gabriel Ostrolucký
25bd41a504 Merge branch '2.14.x' into 2.15.x 2023-03-19 22:46:07 +01:00
Mikael Peigney
a50a611bee docs: Remove incorrect @SequenceGenerator info (#10583)
The default allocationSize for @SequenceGenerator has actually been set to 1 ever since 434325e (back in 2010!)
This was done to remove confusion, but the docs were never updated to reflect the change
2023-03-16 10:32:42 +01:00
David Maicher
abb30093ed add $isXsdValidationEnabled to SimplifiedXmlDriver constructor 2023-03-14 09:38:23 +01:00
Alexander M. Turek
df559d8ac0 PHPStan 1.10.6, Psalm 5.8.0 (#10575) 2023-03-14 07:03:59 +01:00
Cyril Beslay
a6de4b9663 docs: Update Logger removal in Batch Processing documentation (#10572)
Current documented way is using Doctrine DBAL2.
Since DBAL3, logging is done with Middlewares, so I updated the recommendation in documentation.
2023-03-12 00:09:30 +01:00
Grégoire Paris
6db296cd5c Merge pull request #10539 from mpdude/performance-to-one-inheritance
More precisely document the performance impact of to-one associations towards inheritance hierarchies
2023-03-08 23:00:08 +01:00
Matthias Pigulla
7c2adde6f2 More precisely document the performance impact of to-one associations towards inheritance hierarchies
This puts the remarks that apply to both JTI/STI in a common section at the beginning, and tries to explain a bit more in detail why it is that way.

It was sparked off by the discussion in #10538.
2023-03-08 17:27:44 +00:00
Grégoire Paris
04573fc283 Address deprecation of fetchAll() (#10569)
The methods Connection::fetchAll() and Result::fetchAll() have been
deprecated in favor of more their precise counterparts.
2023-03-07 13:17:42 +01:00
Alexander M. Turek
82362ee65e Merge 2.14.x into 2.15.x (#10564) 2023-03-06 09:30:02 +01:00
Grégoire Paris
69543ba1bf Skip test instead of commenting it out (#10563)
Skipping makes the test more discoverable.
2023-03-06 09:27:35 +01:00
Alexander M. Turek
9ff0440aac Merge 2.14.x into 2.15.x (#10561) 2023-03-05 22:35:31 +01:00
Alexander M. Turek
a33885575f Skip test instead of commenting it out (#10560) 2023-03-05 22:24:44 +01:00
Gabriel Ostrolucký
e28dee0742 Add missing return statements to Command:configure methods 2023-03-05 21:31:46 +01:00
Matthias Pigulla
2c40e917c8 Revert unnecessary changes from #10473 2023-03-01 21:30:22 +00:00
Matthias Pigulla
5c06d46874 Add tests for the schema validator check 2023-03-01 21:30:22 +00:00
Matthias Pigulla
24c4ac4dd8 Do not check at runtime that associations do not refer to mapped superclasses 2023-03-01 20:40:55 +00:00
Grégoire Paris
4fad7a1190 Merge pull request #10473 from mpdude/mapped-superclass-resolve-to-many
Allow to-many associations on mapped superclasses w/ ResolveTargetEntityListener
2023-03-01 08:16:07 +01:00
Alexander M. Turek
f36a8c879c Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  Ignore the cache dir of PHPUnit 10 (#10546)
  Make data providers static (#10544)
  Bump dev tools (#10541)
  Mark SqlWalker methods as not deprecated (#10540)
  docs: consistency order for docblock in association mapping (#10534)
  Correct use of PHP attribute
  fix typo in faq.rst (#10526)
  fix: use executeStatement in SchemaTool (#10516)
  Write a test in a more specific way
  Put up a warning sign that mapping may not be inherited from transient classes (#10392)
  Avoid unnecessary information in query hints to improve query cache hit ratio
2023-02-28 13:50:36 +01:00
Alexander M. Turek
a28e2d8277 Ignore the cache dir of PHPUnit 10 (#10546) 2023-02-28 13:35:35 +01:00
Alexander M. Turek
fa4b945b94 Make data providers static (#10545) 2023-02-28 08:29:47 +01:00
Alexander M. Turek
4759a1bf75 Make data providers static (#10544) 2023-02-28 08:29:28 +01:00
Alexander M. Turek
e0ad7ac506 Bump dev tools (#10541)
* phpstan/phpstan (1.9.14 => 1.10.3)
* squizlabs/php_codesniffer (3.7.1 => 3.7.2)
* vimeo/psalm (5.6.0 => 5.7.7)
2023-02-28 08:28:45 +01:00
Christophe Coevoet
9485d4d835 Mark SqlWalker methods as not deprecated (#10540)
phpstan treats implementations of deprecated methods of an interface as being deprecated themselves by default.
However, SqlWalker does not intend to deprecate all those methods that are deprecated in TreeWalker, as they are
moved down. Marking them as not deprecated will avoid reporting usages of deprecated APIs when implementing
custom DQL functions for instance.
2023-02-26 15:21:47 +01:00
Matthias Pigulla
7814cbf4ec Fix a Markdown/RST formatting glitch 2023-02-24 17:59:02 +01:00
Matthieu Lempereur
9a6e1b3505 docs: consistency order for docblock in association mapping (#10534) 2023-02-22 14:00:30 +01:00
Grégoire Paris
c286742814 Merge pull request #10529 from joshpme/patch-1
Correct use of PHP attribute
2023-02-20 08:00:20 +01:00
Josh P
052887765b Correct use of PHP attribute
Incorrect syntax used in php 8 attribute. This should be key: value, rather than key=value
2023-02-20 15:37:30 +11:00
Al Zee
5464e21022 fix typo in faq.rst (#10526) 2023-02-17 08:25:10 +01:00
Grégoire Paris
c26c55926f Merge pull request #8797 from mpdude/query_count_hint 2023-02-15 17:15:45 +01:00
Simon Podlipsky
5369e4f425 fix: use executeStatement in SchemaTool (#10516) 2023-02-14 19:14:28 +01:00
Matthias Pigulla
29bc6cc955 Write a test in a more specific way
... so we can be sure that in fact the second result has a different size.

Co-authored-by: Luís Cobucci <lcobucci@gmail.com>
2023-02-14 08:04:56 +00:00
Grégoire Paris
979b3dcb8d Merge pull request #10513 from greg0ire/use-array-shapes
Use array shapes where appropriate
2023-02-13 23:57:57 +01:00
Matthias Pigulla
8efdcb0555 Deprecate overriding associations not inherited from a mapped superclass 2023-02-13 20:46:11 +00:00
Grégoire Paris
3810a0b6f9 Merge pull request #10470 from mpdude/prevent-entity-override
Deprecate overriding fields/associations inherited from other entities
2023-02-12 18:30:46 +01:00
Matthias Pigulla
c9b644dced Trigger a deprecation notice when entity fields/associations are overridden
This was brought up in #8348, but seemingly forgotten to be implenented in later versions.

Closes #10289.
2023-02-09 22:15:05 +00:00
Grégoire Paris
ae6de13c01 Use array shapes where appropriate
Working on converting these array shapes to DTO allowed me to find every
signature where they are supposed to be used.

The Psalm baseline gets worse because it considers accessing an array
key differently depending on whether it is defined vaguely, as
array<string, mixed>, or precisely, as array{my-key?: string}.
2023-02-09 19:44:47 +01:00
Matthias Pigulla
31ff969628 Put up a warning sign that mapping may not be inherited from transient classes (#10392)
This _seems_ to work, but...

To my understanding, that is only because `ReflectionClass::getProperties` will report `protected` properties also for subclasses, including DocBlocks etc. The mapping drivers are unable to tell where a field comes from, so they pick up the mapping and treat it as originating from the inheriting class.

If that is indeed outside of what the ORM was designed for (sombody please confirm?), then we should explicitly discourage it.

Yes, I have seen examples of this in the wild.
2023-02-09 00:19:38 +01:00
Matthias Pigulla
072c40357f Add mapping configurations for classes that were used in tests as entities, but never declared
Now that we validate association targets, that's an error.
2023-02-08 21:11:59 +00:00
Matthias Pigulla
ca94e82828 Allow to-many associations on mapped superclasses w/ ResolveTargetEntityListener
Allow to-many associations to be used on mapped superclasses when the owning (inverse) side does not refer back to the mapped superclass, thanks to `ResolveTargetEntityListener`.

 #### Current situation

The [documentation states](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html):

> No database table will be created for a mapped superclass itself

> [...] persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all.

That's a though limitation.

~Obviously~ ~apparently~ Probably the limitation comes from the fact that in a to-many association the "many" side has to hold a foreign key. Since the mapped superclass does not have a database table (it's not an entity), no such backreference can be established.

Currently, to-many associations trigger an exception as soon as they are seen on a mapped superclass:

d6c0031d44/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php (L459-L461)

 #### `ResolveTargetEntityListener`

The `ResolveTargetEntityListener` can be used to substitute interface or class names in mapping configuration at runtime, during the metadata load phase.

When this gimmick is used to replace _all_ references to the mapped superclass with an entity class in time, it should be possible to have to-many associations on the inheriting entity classes.

 #### Suggested solution

Instead of rejecting to-many associations on mapped superclasses right away, validate that at the end of the day (after the `loadClassMetadata` event has been processed) no association may target at a non-entity class. That includes mapped superclasses as well as transient classes.

 #### Motivating example

Consider a library that comes with a `User` base class. This class is `abstract` and has to be subclassed/filled when the library is used.

By making this a mapped superclass, library users have the freedom to either have a simple user entity class or a user class hierarchy, but we do not impose any requirements on them. (NB we also don't want to have a root entity in the library, because that would have to declare the entire class hierarchy, including library users' classes.)

The actual user class to be used will be configured through the `ResolveTargetEntityListener`.

The library also includes a `SocialMediaAccount` entity. A `User` can have multiple of these accounts, and we want to be able to navigate the accounts from the user side.

To make the example even more fancy, there is a self-referencing association on the `User`: A `User` has been created by another user, and holds a collection of all other `User`s it created.

The test case contained in this PR contains this example and validates that all association mappings look just as if the final user class had been written as an entity directly, without the superclass.

 #### Potential review talking points

- Am I missing other reasons why to-many is not feasible?
- We now reject association mappings with `targetEntity`s that are not entities; relevant BC break? (IMHO: no.)

 #### Review tip

Review commit by commit, not all files at once. The last commit adds a lot of entity declarations that were previously missed in tests and now raised exceptions; that's a lot of clutter in the PR.
2023-02-08 21:11:58 +00:00
Grégoire Paris
db0b9d13c6 Merge pull request #10511 from doctrine/2.14.x
Merge 2.14.x up into 2.15.x
2023-02-08 22:07:14 +01:00
Alexander M. Turek
01f139d76c Run tests with ext-pgsql (#10480) 2023-02-08 09:33:05 +01:00
Matthias Pigulla
660197ea71 Avoid unnecessary information in query hints to improve query cache hit ratio
I've noticed that over time my query caches fill up with redundant queries, i. e. different cache entries for the DQL -> SQL translation that are exactly the same. For me, it's an issue because the cache entries fill up precious OPcache memory.

Further investigation revealed that the queries themselves do not differ, but only the query hints – that are part of the computed cache key – do.

In particular, only the value for the `WhereInWalker::HINT_PAGINATOR_ID_COUNT` query hint are different. Since `WhereInWalker` only needs to know _if_ there are matching IDs but not _how many_, we could avoid such cache misses by using just a boolean value as cache hint.
2023-02-08 08:19:25 +01:00
Alexander M. Turek
ab06e07b53 Baseline Psalm errors for DBAL 3.6 (#10507) 2023-02-08 07:53:21 +01:00
Grégoire Paris
022b945ed5 Merge pull request #10444 from mpdude/paginator-dql-cacheable
Make Paginator-internal query cacheable in the query cache
2023-02-08 07:53:12 +01:00
Sebastian Busch
7203d05539 Clarify difference between transactional() methods of Connection and EntityManager (#10133)
One could interpret the old description as if `Connection#transactional()` would not rollback the transaction. Also, the fact that the `EntityManager` gets closed in case of an exception was not mentioned.
2023-02-07 23:38:04 +01:00
Alexander M. Turek
6c17e47624 Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  Remove calls to assertObjectHasAttribute() (#10502)
  Remove calls to withConsecutive() (#10501)
  Use recognized array key
  Fix #9095 by re-applying #9096
  Use linebreaks
2023-02-07 01:21:39 +01:00
Alexander M. Turek
0bd5fbf215 Remove calls to assertObjectHasAttribute() (#10502) 2023-02-07 00:13:13 +01:00
Alexander M. Turek
6a713dd39e Remove calls to withConsecutive() (#10501) 2023-02-06 23:23:05 +01:00
Grégoire Paris
5f169d9325 Merge pull request #10420 from mpdude/fix-9095
Fix #9095 by re-applying #9096
2023-02-06 08:23:15 +01:00
Grégoire Paris
cf4680d0e6 Merge pull request #10498 from greg0ire/fix-invalid-test
Use recognized array key
2023-02-06 08:22:26 +01:00
Matthias Pigulla
cc5775c3f4 Make class final (as suggested in GH review) 2023-02-05 21:38:03 +00:00
Grégoire Paris
c5cf6a046b Use recognized array key
"joinColumn" has no meaning for the static PHP driver. That's because it
performs no translation, unlike other drivers: we're using the
ClassMetadata API directly.

Before this change, changing the value of the "name" key did not break
the test suite. After this change, it does.
2023-02-05 14:35:06 +01:00
Matthias Pigulla
77df5db3b9 Make Paginator-internal query cacheable in the query cache
Make the `Paginator`-internal query (`... WHERE ... IN (id, id2,
id3...)`) cacheable in the query cache again.

When the Paginator creates the internal subquery that does the actual
result limiting, it has to take DBAL type conversions for the identifier
column of the paginated root entity into account (#7820, fixed in
 #7821).

In order to perform this type conversion, we need to know the DBAL type
class for the root entity's `#[Id]`, and we have to figure it out based
on a given (arbitrary) DQL query. This requires DQL parsing and
inspecting the AST, so #7821 placed the conversion code in the
`WhereInWalker` where all the necessary information is available.

The problem is that type conversion has to happen every time the
paginator is run, but the query that results from running
`WhereInWalker` would be kept in the query cache. This was reported in
 #7837 and fixed by #7865, by making this particular query expire every
time. The query must not be cached, since the necessary ID type
conversion happens as a side-effect of running the `WhereInWalker`.

The Paginator internal query that uses `WhereInWalker` has its DQL
re-parsed and transformed in every request.

This PR moves the code that determines the DBAL type out of
`WhereInWalker` into a dedicated SQL walker class, `RootTypeWalker`.

`RootTypeWalker` uses a ~hack~  clever trick to report the type back: It
sets the type as the resulting "SQL" string. The benefit is that
`RootTypeWalker` results can be cached in the query cache themselves.
Only the first time a given DQL query has to be paginated, we need to
run this walker to find out the root entity's ID type. After that, the
type will be returned from the query cache.

With the type information being provided, `Paginator` can take care of
the necessary conversions by itself. This happens every time the
Paginator is used.

The internal query that uses `WhereInWalker` can be cached again since
it no longer has side effects.
2023-02-05 11:17:38 +01:00
Matthias Pigulla
ee8269ea55 Fix #9095 by re-applying #9096
Since #10411 has been merged, no more need to specify all intermediate
abstract entity classes.

Thus, we can relax the schema validator check as requested in #9095. The
reasons given in #9142 no longer apply.

Fixes #9095
2023-02-05 11:13:21 +01:00
Grégoire Paris
d038f23570 Use linebreaks 2023-02-05 11:11:21 +01:00
Grégoire Paris
83d56d75e1 Merge remote-tracking branch 'origin/2.14.x' into 2.15.x 2023-02-04 10:09:15 +01:00
Alexander M. Turek
3843d7e0cc Make all data providers static (#10493) 2023-02-04 08:35:56 +00:00
Jan Nedbal
d50ba2e248 Fix invalid phpdocs missing null (#10490) 2023-02-03 22:36:32 +00:00
Jan Nedbal
8debb92d78 Add forgotten exception throws (#10489) 2023-02-03 21:32:13 +00:00
Grégoire Paris
8ff7938e31 Hunt down invalid docblocks (#10476)
It is OK to ignore some of the errors we get, but not this one.
2023-01-31 21:12:00 +01:00
Grégoire Paris
d593c33ffa Merge pull request #10478 from greg0ire/better-psalm-type-location
Move psalm types to ClassMetadata
2023-01-28 16:35:37 +01:00
Grégoire Paris
6c925f5b60 Move psalm types to ClassMetadata
This spares us from referencing ClassMetadataInfo from other classes,
which is a good thing since it is deprecated. It also means merging up
is easier.
2023-01-28 15:40:27 +01:00
Grégoire Paris
82bf68d482 Remove underscore prefix on private variables (#10477) 2023-01-28 15:33:34 +01:00
Grégoire Paris
d6c0031d44 Merge pull request #10453 from mpdude/mapped-superclass-association
Add regression test for a to-many relationship on a base class & mapped superclass in the hierarchy
2023-01-28 11:12:16 +01:00
Alexander M. Turek
2ee936acb4 Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  Psalm 5.6.0, PHPStan 1.9.14 (#10468)
2023-01-26 19:08:35 +01:00
Alexander M. Turek
c78f933e57 Psalm 5.6.0, PHPStan 1.9.14 (#10468) 2023-01-26 19:05:45 +01:00
Matthias Pigulla
843bff4971 Fix some tests that were missed in #10431 (#10464)
In #10431, some invalid inheritance declarations in our test base were fixed. However, the change missed to update XML, PHP and static PHP mapping configurations as well.

Apparently, this did not raise any flags because the misconfiguration only caused a deprecation notice in 2.15.x. Running the tests against 3.0 (where the misconfiguration will be an error) unveiled the mistake.
2023-01-26 19:04:57 +01:00
Matthias Pigulla
d679292861 Remove commented-out code sections (#10465)
This removes comments added in #10431 on the 2.15.x branch, as suggested in https://github.com/doctrine/orm/pull/10460#issuecomment-1404889903.
2023-01-26 14:09:35 +01:00
Matthias Pigulla
65687821a7 Deprecate undeclared entity inheritance (#10431)
Inheritance has to be declared as soon as one entity class extends (directly or through middle classes) another one.

This is also pointed out in the opening comment for #8348:

> Entities are not allowed to extend from entities without an inheritence mapping relationship (Single Table or Joined Table inheritance). [...] While Doctrine so far allowed these things, they are fragile and will break on certain scenarios.

Throwing an exception in case of this misconfiguration is nothing we should do light-heartedly, given that it may surprise users in a bugfix or feature release. So, we should start with a deprecation notice  and make this an exception in 3.0. The documentation is updated accordingly at #10429.

Catching missing inheritance declarations early on is important to avoid weird errors further down the road, giving users a clear indication of the root cause.

In case you are affected by this, please understand that although things "previously worked" for you, you have been using the ORM outside of what it was designed to do. That may have worked in simple cases, but may also have caused invalid results (wrong or missing data after hydration?) that possibly went unnoticed in subtle cases.
2023-01-24 22:47:27 +01:00
Matthias Pigulla
80eb85beaa Add regression test for a to-many relationship on a base class & mapped superclass in the hierarchy
This picks the test case from #9517 and rebases it onto 2.14.x.

The problem has been covered in #8415, so this PR closes #9517 and fixes #9516.

Co-authored-by: Robert D'Ercole <bobdercole@gmail.com>
2023-01-24 20:47:41 +00:00
Grégoire Paris
ca0dffb53e Merge remote-tracking branch 'origin/2.14.x' into 2.15.x 2023-01-23 19:27:03 +01:00
Grégoire Paris
01028cf3b8 Merge commit '8b2854393' into 2.15.x 2023-01-23 19:20:22 +01:00
Grégoire Paris
84bfe7cbb9 Merge pull request #10446 from greg0ire/update-psalm-baseline
Update Psalm baseline
2023-01-23 19:20:00 +01:00
Grégoire Paris
1b3978e8c9 Update Psalm baseline 2023-01-23 19:17:40 +01:00
Alexander M. Turek
ed56f42cd5 Psalm 5.5.0 (#10445) 2023-01-23 17:33:19 +01:00
Matthias Pigulla
8b28543939 Avoid wasting Opcache memory with Paginator queries (#10434)
This PR prevents the Paginator from causing OpCache "wasted memory" to increase _on every request_ when used with Symfony's `PhpFilesAdapter` as the cache implementation for the query cache.

Depending on configured thresholds, wasted memory this will either cause periodic opcache restarts or running out of memory and not being able to cache additional scripts ([Details](https://tideways.com/profiler/blog/fine-tune-your-opcache-configuration-to-avoid-caching-suprises)).

Fixes #9917, closes #10095.

There is a long story (#7820, #7821, #7837, #7865) behind how the Paginator can take care of DBAL type conversions when creating the pagination query. This conversion has to transform identifier values before they will be used as a query parameter, so it has to happen every time the Paginator is used.

For reasons, this conversion happens inside `WhereInWalker`. Tree walkers like this are used only during the DQL parsing/AST processing steps. Having a DQL query in the query cache short-cuts this step by fetching the parsing/processing result from the cache.

So, to make sure the conversion happens also with the query cache being enabled, this line

1753d03500/lib/Doctrine/ORM/Tools/Pagination/Paginator.php (L165)

was added in #7837. It causes `\Doctrine\ORM\Query::parse()` to re-parse the query every time, but will also put the result into the query cache afterwards.

At this point, the setup described in #9917 – which, to my knowledge, is the default in Symfony + DoctrineBundle projects – will ultimately bring us to this code:

4b3391725f/src/Symfony/Component/Cache/Adapter/PhpFilesAdapter.php (L248-L249)

When writing a cache item with an already existing key, the driver has to make sure the opcache will honor the changed PHP file. This is what causes _wasted memory_ to increase.

Instead of using `\Doctrine\ORM\Query::expireQueryCache()`, which will force `\Doctrine\ORM\Query::parse()` to parse the query again before putting it into the cache, use `\Doctrine\ORM\Query::useQueryCache(false)`. The subtle difference is the latter will not place the processed query in the cache in the first place.

A test case is added to check that repeated use of the paginator does not call the cache to update existing keys. That should suffice to make sure we're not running into the issue, while at the same time not complicating tests by using the `PhpFilesAdapter` directly.

Note that in order to observe the described issue in tests, you will need to use the `PhpFilesDriver` and also make sure that OpCache is enabled and also activated for `php-cli` (which is running the unit tests).

This particular subquery generated/used by the Paginator is not put into the query cache. The DQL parsing/to-SQL conversion has to happen _every time_ the Paginator is used.

This, however, was already the case before this PR. In other words, this PR only changes that we do not store/update the cached result every time, but instead completely omit caching the query.
2023-01-23 13:14:46 +01:00
Javier Spagnoletti
eec3c42494 Replace hardcoded name with Command::getName() in output message from UpdateCommand (#10443) 2023-01-23 12:51:16 +01:00
Grégoire Paris
7f783b59c8 Merge pull request #10442 from greg0ire/embedded-class-array-shape 2023-01-23 10:58:11 +01:00
Grégoire Paris
68662f5920 Add embedded class mapping array shape
This should be replaced with a DTO in the next major.
To be able to have something usable, I had to move the validation of the
DTO (checking that it has a "class" attribute) to mapEmbedded, which
happens earlier than doLoadMetadata(). It is unclear to me why it was
not put here in the first place.
2023-01-22 23:49:43 +01:00
Adrien Crivelli
769b161dff Identity map cannot contain null value (#10156) 2023-01-22 14:15:20 +07:00
Grégoire Paris
bc394877bc Use the right property (#10441) 2023-01-22 14:04:12 +07:00
Grégoire Paris
1753d03500 Merge pull request #10433 from mpdude/re-enable-tests-7820
Make sure tests from #7837 are actually run
2023-01-21 10:02:34 +01:00
Grégoire Paris
9857cf971b Merge pull request #10438 from greg0ire/2.15.x
Merge 2.14.x up into 2.15.x
2023-01-20 23:58:44 +01:00
Grégoire Paris
f73dae9bc4 Merge remote-tracking branch 'origin/2.14.x' into 2.15.x 2023-01-20 21:19:28 +01:00
Grégoire Paris
1c357b9fb3 Merge pull request #10426 from mpdude/parent-classes-docblock
Slight docblock improvements for `CM::parentClasses`
2023-01-20 12:46:34 +01:00
Matthias Pigulla
3d031ed541 Slight docblock improvements for CM::parentClasses 2023-01-20 11:26:28 +00:00
Grégoire Paris
15ed97b7b1 Merge pull request #10437 from greg0ire/update-baseline
Update Psalm baseline
2023-01-20 12:03:42 +01:00
Grégoire Paris
9fd4af23e1 Update Psalm baseline 2023-01-20 12:00:34 +01:00
Grégoire Paris
7ce6d8d427 Merge pull request #10436 from greg0ire/update-baseline
Update Psalm baseline
2023-01-20 11:43:52 +01:00
Grégoire Paris
a48d95c71d Update Psalm baseline 2023-01-20 11:42:11 +01:00
Matthias Pigulla
aee1d33042 Review the documentation regarding entity inheritance (#10429)
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-01-19 19:59:28 +01:00
Matthias Pigulla
8da741ad75 Make sure tests from 7820 are actually run 2023-01-19 12:05:32 +00:00
Grégoire Paris
4206f01e7b Use FieldMapping array shape even more (#10430)
I experimented on converting FieldMapping to a DTO, and it allowed me to
find more places where it should be used.
2023-01-19 10:06:03 +01:00
Matthias Pigulla
7d4052c9e7 Fix version number in UPGRADE.md (#10428)
This was a mistake in #10423.
2023-01-19 08:23:27 +01:00
Grégoire Paris
fc6feb5938 Merge pull request #10423 from mpdude/deprecate-table-type-per-class
Add deprecations for "table per class" inheritance
2023-01-18 23:23:53 +01:00
Matthias Pigulla
89b98bdff9 Add deprecations for "table per class" inheritance 2023-01-18 16:30:57 +00:00
Matthias Pigulla
ba7387fd8c Fixup GH8127 test case (#10424)
* Fixup GH8127 test case

This removes the unnecessary "middle2" class and puts back in the effect of the data provider.

Both changes were accidentally committed when I was working on #10411 and just meant as experiments during debugging.

* Fix CS
2023-01-18 14:42:26 +01:00
Grégoire Paris
a83e4f7978 Merge pull request #10418 from greg0ire/unique-bool
Use correct type for FieldMapping#unique
2023-01-18 07:37:15 +01:00
Grégoire Paris
4f335ab565 Merge pull request #10415 from greg0ire/maintain-psalm-xml
Remove ignore rules for fixed issues
2023-01-18 07:36:27 +01:00
Grégoire Paris
f88b0032ad Use correct type for FieldMapping#unique
Looking at usages in the codebase, it is supposed to be at least
bool|string, but not string.
When dumping the value inside `getFieldMapping`, it is always a boolean.
2023-01-17 16:29:07 +01:00
Grégoire Paris
69c7791ba2 Merge pull request #8415 from mpdude/mapped-superclass-association-inheritance
Fix association handling when there is a MappedSuperclass in the middle of an inheritance hierarchy
2023-01-17 16:25:20 +01:00
Grégoire Paris
1090dbe9be Merge pull request #10411 from mpdude/discover-missing-subclasses
Fill in missing subclasses when loading ClassMetadata
2023-01-17 16:13:53 +01:00
Matthias Pigulla
c46b604ed7 Fix CS 2023-01-17 14:40:55 +00:00
Matthias Pigulla
8d9ebeded8 Fix association handling when there is a MappedSuperclass in the middle of an inheritance hierarchy
This fixes two closely related bugs.

1. When inheriting a to-one association from a mapped superclass, update the `sourceEntity` class name to the current class only when the association is actually _declared_ in the mapped superclass.
2. Reject association types that are not allowed on mapped superclasses only when they are actually _declared_ in a mapped superclass, not when inherited from parent classes.

Currently, when a many-to-one association is inherited from a `MappedSuperclass`, mapping information will be updated so that the association has the current (inheriting) class as the source entity.

2138cc9383/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php (L384-L393)

This was added in 7dc8ef1db9 for [DDC-671](https://github.com/doctrine/orm/issues/5181).

The reason for this is that a mapped superclass is not an entity itself and has no table.

So, in the database, associations can only be from the inheriting entities' tables towards the referred-to target. This is also the reason for the limitation that only to-one associations may be added in mapped superclasses, since for those the database foreign key can be placed on the table(s) of the inheriting entities (and there may be more than one child class).

Neither the decision to update the `sourceEntity` nor the validation check should be based on `$parent->isMappedSuperclass`.

This only works in the simple case where the class hierarchy is `Mapped Superclass → Entity`.

The check is wrong when we have an inheritance hierarchy set up and the class hierarchy is `Base Entity → Mapped Superclass → Child Entity`.

Bug 1: The association should keep the root entity as the source. After all, in a JTI, the root table will contain the foreign key, and we need to base joins on that table when traversing `FROM LeafClass l JOIN l.target`.

Bug 2: Do not reject the to-many association declared in the base class. It is ok to have the reverse (owning) side point back to the base entity, as it would be if there were no mapped superclasses at all. The mapped superclass does not declare, add or otherwise interfere with the to-many association at all.

Base the decision to change the `sourceEntity` on `$mapping['inherited']` being set. This field points to the topmost _parent entity_ class in the ancestry tree where the relationship mapping appears for the first time.

When it is not set, the current class is the first _entity_ class in the hierarchy with that association. Since we are inheriting the relation, it must have been added in a mapped superclass above, but was not yet present in the nearest parent entity class.

In that case, it may only be a to-one association and the source entity needs to be updated.

(See #10396 for a clarification of the semantics of `inherited`.)

Here is a simplified example of the class hierarchy.

See the two tests added for more details – one is for checking the correct usage of a to-one association against/with the base class in JTI. The other is to test that a to-many association on the base class is not rejected.

I am sure that there are other tests that (still) cover the update of `sourceEntity` is happening.

```php
/**
 * @Entity
 */
class AssociationTarget
{
    /**
     * @Column(type="integer")
     * @Id
     * @GeneratedValue
     */
    public $id;
}

/**
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discriminator", type="string")
 * @DiscriminatorMap({"1" = "BaseClass", "2" = "LeafClass"})
 */
class BaseClass
{
    /**
     * @Column(type="integer")
     * @Id
     * @GeneratedValue
     */
    public $id;

    /**
     * @ManyToOne(targetEntity="AssociationTarget")
     */
    public $target;
}

/**
 * @MappedSuperclass
 */
class MediumSuperclass extends BaseClass
{
}

/**
 * @Entity
 */
class LeafClass extends MediumSuperclass
{
}
```

When querying `FROM LeafClass l`, it should be possible to `JOIN l.target`. This currently leads to an SQL error because the SQL join will be made via `LeafClass.target_id` instead of `BaseClass.target_id`. `LeafClass` is considered the `sourceEntity` for the association – which is wrong–, and so the foreign key field is expected to be in the `LeafClass` table (using JTI here).

Fixes #5998, fixes #7825.

I have removed the abstract entity class, since it is not relevant for the issue and took the discussion off course. Also, the discriminator map now contains all classes.

Added the second variant of the bug, namely that a to-many association would wrongly be rejected in the same situation.
2023-01-17 14:37:40 +00:00
Grégoire Paris
55f9178e84 Remove ignore rules for fixed issues
The ArgumentTypeCoercion one is hiding issues we could address.
Addressing them will require changes that should go in the next minor,
so I'm moving them to the baseline instead. That way, we cannot
introduce more issues of this type in this file.
2023-01-17 15:34:10 +01:00
Grégoire Paris
37572802cc Reuse association mapping array shape (#10403) 2023-01-17 11:27:42 +01:00
Matthias Pigulla
60955755e0 Remove outdated todo 2023-01-17 08:49:36 +00:00
Grégoire Paris
a5bdc619c7 Merge pull request #10408 from greg0ire/field-mapping-improvements
Field mapping improvements
2023-01-17 09:08:33 +01:00
Matthias Pigulla
a8e979819a Include a test for DDC-6558 2023-01-16 21:13:30 +00:00
Matthias Pigulla
4e8e3ef30b Discover entity subclasses that need not be declared in the discriminator map 2023-01-16 20:33:25 +00:00
Grégoire Paris
65a7c8882f Merge pull request #10413 from doctrine/2.14.x-merge-up-into-2.15.x_2sgwy6Oi
Merge release 2.14.1 into 2.15.x
2023-01-16 20:44:54 +01:00
Grégoire Paris
2d6295c9db Merge remote-tracking branch 'origin/2.14.x' into 2.15.x 2023-01-16 20:24:44 +01:00
Grégoire Paris
de7eee5ed7 Merge pull request #10385 from nicolas-grekas/uninitialized-prop-reproducer
Fix initializing lazy objects and get rid of "Typed property must not be accessed before initialization" errors
2023-01-16 19:36:59 +01:00
Grégoire Paris
4051937fda Merge pull request #10412 from ThomasLandauer/patch-8
Adding link to Attributes reference
2023-01-16 19:35:20 +01:00
Thomas Landauer
b2e42dc92d Adding link to Attributes reference
In fact, I moved it upwards, and updated it to new target :-)
2023-01-16 17:19:29 +01:00
Alexander M. Turek
f0616626e0 Test with a stable PHPUnit (#10406) 2023-01-16 15:53:19 +07:00
Grégoire Paris
f219b87870 Merge pull request #10393 from mpdude/traits-warning
Place a warning about the uses of traits in the documentation
2023-01-16 08:56:11 +01:00
Matthias Pigulla
a8ef69dbe6 Factor out logic that tracks mapping inheritance (#10397) 2023-01-16 06:33:54 +04:00
Grégoire Paris
c0a7317e8d Reuse array shape 2023-01-15 21:55:32 +01:00
Grégoire Paris
843b0fcc16 Add missing fields 2023-01-15 21:55:32 +01:00
Grégoire Paris
b56de5b0e2 Type TypedFieldMapper API more precisely 2023-01-15 21:55:32 +01:00
Grégoire Paris
87fefbac34 Merge pull request #10396 from mpdude/document-inherited-declared-meaning
Document the meanings of 'inherited' and 'declared' in field mapping information
2023-01-15 15:40:38 +01:00
Alexander M. Turek
0b35e637b8 Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  Stop allowing phpbench's master branch
2023-01-15 14:54:24 +07:00
Matthias Pigulla
853e80ca98 Reword text 2023-01-14 22:56:23 +00:00
Grégoire Paris
d68baef880 Merge pull request #10404 from greg0ire/stable-phpbench
Stop allowing phpbench's master branch
2023-01-14 20:44:08 +01:00
Grégoire Paris
fdccfbd120 Stop allowing phpbench's master branch
A stable version has been published, it allows doctrine/annotations 2
2023-01-14 16:41:18 +01:00
Grégoire Paris
277614d9c2 Merge pull request #10400 from doctrine/2.14.x
Merge 2.14.x up into 2.15.x
2023-01-14 11:10:20 +01:00
Matthias Pigulla
180afa8c8f Write down what "transient" means (#10394)
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-01-14 10:33:58 +01:00
Grégoire Paris
dbbf5c7279 Merge pull request #10390 from greg0ire/wrong-phpdoc-exception
Use more accurate phpdoc for OptimisticLockException
2023-01-14 10:29:13 +01:00
Grégoire Paris
5d9b8f0ea8 Merge pull request #10399 from mpdude/fix-toothbrush-example
Fix DDL example for Mapped Superclasses
2023-01-14 10:28:24 +01:00
Matthias Pigulla
174947155d Fix DDL example for Mapped Superclasses
This was not updated to reflect the changes made when the example was improved in b3ee7141eb.
2023-01-14 08:14:04 +00:00
Grégoire Paris
2138cc9383 Sync variable name with class name (#10395) 2023-01-14 00:16:41 +01:00
Matthias Pigulla
39a434914d Be more vague about the Entity Generator 2023-01-13 23:04:40 +00:00
Matthias Pigulla
227f60c832 Update lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2023-01-13 23:51:39 +01:00
Matthias Pigulla
f72f6b199b Document the meanings of 'inherited' and 'declared' in field mapping information 2023-01-13 22:35:36 +00:00
Matthias Pigulla
92e63ca4f9 Place a warning about the uses of traits in the documentation 2023-01-13 13:33:53 +00:00
Grégoire Paris
3c98973ab3 Use more accurate phpdoc for OptimisticLockException
While working on migrating this part of the codebase to PHP 8, I found
phpdoc that is wrong.
2023-01-12 18:01:17 +01:00
Kevin Bond
3b8692fa4a add reproducer 2023-01-09 16:09:03 +01:00
Nicolas Grekas
c9efc1cdee Fix initializing lazy objects and get rid of "Typed property must not be accessed before initialization" errors 2023-01-09 15:58:20 +01:00
Alexander M. Turek
29b8b0bffb Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  PHPStan 1.9.8, Psalm 5.4.0 (#10382)
  fix typo for missing a comma (#10377)
  Docs: Removing `type: 'integer'` from mappings (#10368)
  Docs: Moving *attributes* mapping to first position (#10364)
  Docs: Deleting duplicate mapping example (#10363)
2023-01-09 11:32:00 +07:00
Grégoire Paris
b7ba018f0a Use more precise types for class strings (#10381) 2023-01-09 11:29:56 +07:00
Alexander M. Turek
c5e4e41e05 PHPStan 1.9.8, Psalm 5.4.0 (#10382) 2023-01-09 11:16:44 +07:00
fauVictor
9431b2ea45 fix typo for missing a comma (#10377) 2023-01-06 16:31:05 +01:00
Grégoire Paris
72b1bf0c02 Use the same type as in the DBAL (#10372)
* Use the same type as in the DBAL

Implementations pass this parameter unchanged to DBAL methods.

* Update Psalm baseline
2023-01-04 19:32:28 +01:00
Thomas Landauer
036ea713a5 Docs: Removing type: 'integer' from mappings (#10368)
Yet another micro-PR ;-) - as requested at https://github.com/doctrine/orm/pull/10364#issuecomment-1370155521

I also changed `$currentPrice` from `float` to `int`, since IMO it's better to store prices as `int` (=cents).

Question: Is there a reason why most typehints are `int|null`, instead of `?int`? Should I change them?
2023-01-04 00:16:22 +01:00
Grégoire Paris
70241d3407 Merge pull request #10365 from greg0ire/precise-return-type
Address new behavior of $firstResult
2023-01-03 23:55:01 +01:00
Thomas Landauer
0852847659 Docs: Moving *attributes* mapping to first position (#10364) 2023-01-03 22:42:12 +01:00
Grégoire Paris
1d5d47964c Address new behavior of $firstResult
Following 1915dcd1e8, 0 is now used as a
default value, and Query::$firstResult is no longer nullable, but it
seems getFirstResult() was overlooked. The class is final, so this is no
breaking change.
2023-01-03 21:29:09 +01:00
Thomas Landauer
1e2625a82f Docs: Deleting duplicate mapping example (#10363)
I'm guessing this was forgotten to delete some time ago...
2023-01-03 20:43:26 +01:00
Alexander M. Turek
c9c4203a1e Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  PHPStan 1.9.5 (#10359)
2023-01-02 23:14:10 +01:00
Alexander M. Turek
3010fd1680 PHPStan 1.9.5 (#10359) 2023-01-02 23:12:40 +01:00
Grégoire Paris
091da8c420 Merge pull request #10329 from greg0ire/drop-lexer-1-backport
Drop doctrine/lexer 1
2023-01-02 21:07:13 +01:00
Alexander M. Turek
515a3d8b8b Merge branch '2.14.x' into 2.15.x
* 2.14.x:
  Shorter deprecation message (#10357)
  Add Fully-Qualified class name in UnrecognizedField exception to ease debugging (#10342)
  Include parameter types in hydration cache key generation (#10355)
2022-12-31 17:45:59 +01:00
Alexander M. Turek
85ac2769a9 Shorter deprecation message (#10357) 2022-12-31 17:43:12 +01:00
Axel Venet
28e98b3475 Add Fully-Qualified class name in UnrecognizedField exception to ease debugging (#10342) 2022-12-31 15:20:29 +01:00
Alexander M. Turek
99a37d864e Include parameter types in hydration cache key generation (#10355) 2022-12-31 00:44:23 +01:00
Grégoire Paris
603ab9a185 Drop doctrine/lexer 1 2022-12-31 00:20:27 +01:00
Alexander M. Turek
10d27c18ea Allow doctrine/instantiator 2 (#10351) 2022-12-30 19:52:12 +01:00
Alexander M. Turek
ae9fb8ca21 Merge 2.14.x into 2.15.x (#10344) 2022-12-28 17:23:15 +01:00
Rémi San
c7f2a1d580 Support of NOT expression from doctrine/collections ^2.1 (#10234) 2022-12-28 17:22:39 +01:00
Alexander M. Turek
27df173971 Fix Psalm errors with Collection 2.1.2 (#10343) 2022-12-28 17:19:21 +01:00
Antonio Norman
0aa45dd607 Added warning about query cache in relation to parameters (#10276)
* Added warning about query cache in relation to parameters

* Updated warning about query cache in relation to parameters

* Update docs/en/reference/filters.rst

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

* Update docs/en/reference/filters.rst

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

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2022-12-24 23:01:28 +01:00
Grégoire Paris
b3f441cb8b Merge pull request #10330 from doctrine/2.14.x
Merge 2.14.x up into 2.15.x
2022-12-20 20:07:49 +01:00
Grégoire Paris
f8bf84d1aa Merge pull request #10088 from HypeMC/enums-in-simpleobjecthydrator 2022-12-20 16:50:24 +01:00
michnovka
c825e34f8d Improve and fix TypedFieldMapper docs (#10327) 2022-12-20 13:09:59 +01:00
Grégoire Paris
ff6bad486b Require dev version of phpbench (#10328)
It is important to have the same version of all dependencies in dev and
in the CI, otherwise it makes it hard to have the right static analysis
baseline for every environment.
2022-12-20 09:18:23 +01:00
Grégoire Paris
30a2680bfd Merge pull request #10325 from greg0ire/update-branch-metadata
Update branch metadata
2022-12-19 23:48:49 +01:00
Grégoire Paris
a460a4d054 Update branch metadata 2022-12-19 23:35:07 +01:00
Alexander M. Turek
f82485e651 Support doctrine/annotations 2 (#10320) 2022-12-19 22:51:58 +01:00
Grégoire Paris
c4835cca0d Drop forceful loading of annotations (#10321)
Since doctrine/annotations 1.10, autoloading is used when everything
else has failed. Using registerFile() has been deprecated in favor of
that later on.
2022-12-19 20:12:23 +01:00
Alexander M. Turek
82a406332e Document stdClass structures used by CommitOrderCalculator (#10315) 2022-12-19 15:43:46 +01:00
Alexander M. Turek
8093c2eef6 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Psalm 5.3.0 (#10317)
  PHPStan 1.9.4 (#10318)
2022-12-19 15:22:24 +01:00
Alexander M. Turek
099e51d899 Psalm 5.3.0 (#10317) 2022-12-19 15:04:28 +01:00
Alexander M. Turek
5df84d4ec0 PHPStan 1.9.4 (#10318) 2022-12-19 12:16:41 +01:00
Alexander M. Turek
f94cb9a5e6 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  add apcu enabled check if apcu extension loaded (#10310) (#10311)
2022-12-19 00:23:32 +01:00
aleksejs1
c23220b68a add apcu enabled check if apcu extension loaded (#10310) (#10311)
* add apcu enabled check if apcu extension loaded (#10310)

* Apply suggestions from code review

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* add use function apcu_enabled

* enable apcu_cli for cache tests

Co-authored-by: Aleksejs Kovalovs <kovalovs@co.inbox.lv>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2022-12-18 21:21:27 +01:00
michnovka
6255461b84 Add TypedFieldMapper for automatic mapping of typed PHP fields to DBAL types (#10313)
Previously, only a predefined set of automatic mappings was allowed, such as int, float, boolean, DateTime etc.
With this extension, it is possible to supply custom TypedFieldMapper implementation which takes as parameter the ReflectionProperty of a given field and decides the appropriate mapping.
A new configuration option was added to set and get the TypedFieldMapper.
The old logic was moved into a class DefaultTypedFieldMapper which is used by default when no mapper is supplied.
The selected TypedFieldMapper is passed into ClassMetadataInfo constructor. If empty, the DefaultTypedFieldMapper is used.
There is also ChainTypedFieldMapper class which allows chaining multiple TypedFieldMappers and apply them in a cascade (always if a field gets type assigned by the earlier mapper in the list, it will not be changed later).
2022-12-18 21:08:30 +01:00
Grégoire Paris
0aa5946286 Merge pull request #10301 from greg0ire/allow-lexer-2
Allow lexer 2
2022-12-14 20:29:27 +01:00
Grégoire Paris
eda7558674 Allow doctrine/lexer 2 2022-12-14 13:49:51 +01:00
Grégoire Paris
13bab31da6 Merge pull request #10302 from greg0ire/non-nullability-assertions
Add assertions about non nullability
2022-12-13 23:22:19 +01:00
Grégoire Paris
f960bc2c11 Add assertions about non nullability 2022-12-13 21:13:38 +01:00
Grégoire Paris
15058ca83e Merge pull request #10288 from michnovka/2.13.x-enum-discriminator-columns
Allow enum discriminator columns
2022-12-13 20:01:31 +01:00
Alexander M. Turek
9b14786738 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Bump coding standard to v11 (#10295)
  PHPStan 1.9.3 (#10298)
  Rename AbstractCommandTest (#10294)
2022-12-13 19:09:05 +01:00
Alexander M. Turek
83f6356f25 Bump coding standard to v11 (#10295) 2022-12-13 19:08:04 +01:00
Alexander M. Turek
4e6cb908f6 PHPStan 1.9.3 (#10298) 2022-12-13 18:51:58 +01:00
Tomas
497ee166bd Add support for enum discriminator columns
This commit adds enumType option to DiscriminatorColumn as well as support for custom DBAL types which use PHP enums for PHP values.
Previously, the enumType option was completely missing, but also even using custom types that used PHP enums would end up in exception because ObjectHydrator would try to convert enums to string using (string) explicit conversion.
Apart from hydrators, ClassMetadataBuilder was extended to support specifying enumType.
Documentation was updated.
2022-12-13 11:15:39 +01:00
Alexander M. Turek
9b723a88aa Rename AbstractCommandTest (#10294) 2022-12-12 16:36:16 +01:00
Alexander M. Turek
db18161a1a Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Fix changeset computation for enum arrays (#10277)
  Psalm 5.2.0 (#10291)
  Run tools on PHP 8.2 (#10287)
2022-12-12 13:59:45 +01:00
michnovka
bd11475615 Fix changeset computation for enum arrays (#10277)
Previously, array of enums were incorrectly compared in UoW::computeChangeSet() resulting always in false positive, since the original data for comparison is fetched using ReflectionEnumProperty::getValue(), which returns the enum values, not enum objects.
This fix ensures comparing the individual enum array members' values.
2022-12-12 13:58:21 +01:00
Alexander M. Turek
90f1f54e73 Psalm 5.2.0 (#10291) 2022-12-12 13:54:50 +01:00
Alexander M. Turek
b25561ad96 Run tools on PHP 8.2 (#10287) 2022-12-11 11:58:09 +01:00
Alexander M. Turek
284e81403b Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Fix association mapping with enum fields
  Correct spelling errors
2022-12-10 18:32:48 +01:00
Alexander M. Turek
3ea8550ca6 Control proxy implementation via env (#10282) 2022-12-10 18:11:02 +01:00
Grégoire Paris
aa4b62ce78 Merge pull request #10187 from nicolas-grekas/ve-proxy-2
Leverage LazyGhostTrait when possible
2022-12-09 14:14:42 +01:00
Nicolas Grekas
e5e674c686 Leverage LazyGhostTrait when possible 2022-12-08 22:09:29 +01:00
Grégoire Paris
b391431a0e Merge pull request #10274 from michnovka/2.13.x-complex-enum-ids
Fix enum IDs in association mappings
2022-12-08 08:59:52 +01:00
Tomas
d5a6b36e6f Fix association mapping with enum fields
Enum fields as ID have worked for some time, but referencing these fields from other entities in association mappings such as OneToOne, ManyToOne and ManyToMany resulted in fatal error as there was an attempt to convert enum value to string improperly.
2022-12-07 16:56:35 +01:00
HypeMC
9d5ab4ce76 Ensure consistent original data with enums
Previously different hydrators would store the original data for enum
fields in different ways, the SimpleObjectHydrator would keep them as
strings while other hydrators would convert then to native php enums.

This would make the data in the internal UnitOfWork::$originalEntityData
array inconsistent which could've caused problems in the long run.

Now, all hydrators convert enum fields to native php enums ensuring the
original data is always consistent regardless of the hydrator used.
2022-12-07 04:54:22 +01:00
Alexander M. Turek
a2b5bae923 Fix deprecation message (#10270) 2022-12-05 21:45:50 +01:00
Grégoire Paris
aeed977d6e Merge pull request #10271 from kalifg/patch-1
Correct spelling errors
2022-12-05 19:43:18 +01:00
Michael Dwyer
f66b008b8b Correct spelling errors 2022-12-05 12:31:10 -06:00
Alexander M. Turek
5a8541b450 Add $not constructor parameter to AST classes (#10267) 2022-12-05 11:44:53 +01:00
Grégoire Paris
fa18e130cb Merge pull request #10265 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-12-04 00:12:25 +01:00
Grégoire Paris
2ed3f55c01 Merge pull request #10264 from greg0ire/psalm-5.1
Upgrade to Psalm 5.1.0
2022-12-04 00:00:18 +01:00
Grégoire Paris
2dfb4f44e2 Upgrade to Psalm 5.1.0 2022-12-03 10:58:00 +01:00
Alexander M. Turek
24bf06725b Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Bump Psalm to 5.0.0 and fix errors for Symfony 6.2 (#10261)
  Leverage Lexer's Token type (follow up)
2022-11-30 22:01:47 +01:00
Alexander M. Turek
4b577e7a18 Bump Psalm to 5.0.0 and fix errors for Symfony 6.2 (#10261) 2022-11-30 22:00:40 +01:00
Grégoire Paris
d5ef6be4cc Merge pull request #10256 from greg0ire/parser-consistent-style
Make use statements redundant
2022-11-27 21:59:00 +01:00
Grégoire Paris
65da1fe8cb Merge pull request #10257 from greg0ire/fix-phpdoc-parser
Leverage Lexer's Token type (follow up)
2022-11-27 21:53:55 +01:00
Grégoire Paris
54336840e6 Make use statements redundant
In 68bc00b6c6, while fixing coding style,
I introduced many, many use statements in that file. Using
half-qualified names sometimes, and unqualified names some other times
makes no sense.

If AST\ is used at least once, use it always.
2022-11-26 17:09:39 +01:00
Grégoire Paris
74986f1d53 Merge pull request #10253 from greg0ire/2.14.x
Merge 2.13.x up into 2.14.x
2022-11-26 14:35:02 +01:00
Grégoire Paris
1df221860f Leverage Lexer's Token type (follow up)
Follow-up of f82db6a894.
The previous value introduced in
dc37c2cd2f was too restrictive, hence the
changes to the Psalm baseline.
2022-11-26 14:24:02 +01:00
Grégoire Paris
16cd49ba89 Merge remote-tracking branch 'origin/2.13.x' into 2.14.x 2022-11-26 14:18:14 +01:00
Grégoire Paris
57ac275137 Merge pull request #10252 from greg0ire/psalm-5
Upgrade to Psalm v5
2022-11-26 14:11:21 +01:00
Grégoire Paris
e958046c4a Upgrade to Psalm v5
It is not stable yet, but should be good enough, and this will help
taking care of #10118

Let us baseline all the new issues, just because they are new does not
mean they are more important than already-baselined errors. Besides, it
is more important to have higher standards for new code than to get an
increased baseline.
2022-11-26 13:41:02 +01:00
Grégoire Paris
3038f6aeef Psalm 5 fixes (#10248)
* Account for ClassMetadata::inheritanceType always being truthy

* Remove redundant cast to array
2022-11-24 21:28:23 +01:00
Grégoire Paris
28bf6cb1fa Merge pull request #10247 from derrabus/sa/paginator
Fix types for Paginator
2022-11-23 21:49:53 +01:00
Alexander M. Turek
e864c4cbc2 Fix types for Paginator 2022-11-23 21:40:17 +01:00
Grégoire Paris
f9d5a89a39 Merge pull request #10242 from VincentLanglet/staticAnalysis
Solve some PHPStan baseline errors
2022-11-21 08:09:27 +01:00
Vincent Langlet
db7333cc84 Update baseline 2022-11-20 23:55:47 +01:00
Vincent Langlet
47b4ccc4e6 Solve some baseline errors 2022-11-20 22:49:51 +01:00
Grégoire Paris
5a7fce12b8 Merge pull request #10238 from VincentLanglet/lockMode
Use more precise phpdoc
2022-11-20 22:20:08 +01:00
Vincent Langlet
cc9e456ed8 Use more precise phpdoc 2022-11-20 21:56:59 +01:00
Alexander M. Turek
da356316c1 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Remove fragile assertions (#10239)
2022-11-20 20:57:47 +01:00
Grégoire Paris
a5a6cc6630 Remove fragile assertions (#10239)
RuntimePublicReflectionProperty has been deprecated in favor of
RuntimeReflectionProperty.

Let us use a more robust assertion.
2022-11-20 19:53:31 +01:00
Grégoire Paris
1ce806fcb7 Merge pull request #10231 from greg0ire/static-analysis-improvements
Make the code easier to statically analyse
2022-11-16 08:08:49 +01:00
David Maicher
958d0b6193 update help for RunDqlCommand (#10233) 2022-11-15 17:38:56 +01:00
Grégoire Paris
843f3c3b23 Make the code easier to statically analyse 2022-11-14 23:00:25 +01:00
Grégoire Paris
82e4c644f9 Merge pull request #10230 from greg0ire/2.14.x
Merge 2.13.x up into 2.14.x
2022-11-14 22:50:32 +01:00
Grégoire Paris
9399f1f3a8 Merge remote-tracking branch 'origin/2.13.x' into 2.14.x 2022-11-14 22:43:56 +01:00
Grégoire Paris
fc3201bded Merge pull request #10229 from greg0ire/fix-phpdoc-exception
Widen parameter type
2022-11-14 22:15:29 +01:00
Grégoire Paris
ad69810775 Merge pull request #10224 from greg0ire/fix-wrong-phpdoc
Document property as non-nullable
2022-11-13 22:11:54 +01:00
Grégoire Paris
3178b4ec4f Widen parameter type
This exception is used in two places, one where $generatedMode is
clearly a string, and another where typing it as a string will cause a
type error, because $generatedMode is supposed to be an int there.
2022-11-13 19:13:40 +01:00
Grégoire Paris
6c7a5e6faa Document property as non-nullable
The constructor forbids it.
2022-11-11 18:39:25 +01:00
Grégoire Paris
dcc1c26826 Merge pull request #10222 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-11-11 16:31:42 +01:00
Grégoire Paris
465c02fe68 Reverse-engineer actual type from code (#10221)
The code contains tests for is_array(), is object(), and an else clause.
The type is wrong, and the variable name misleading.
2022-11-11 16:29:36 +01:00
Grégoire Paris
8afb644a18 Ignore PropertyNotSetInConstructor (#10218)
Inside the Query\AST namespace, many classes use public properties that
are supposed to be set from outside the class. Let us ignore
PropertyNotSetInConstructor for that entire namespace instead of doing
it on a case by case basis.
2022-11-11 14:56:31 +01:00
Alexander M. Turek
953e42d059 Add a constructor to CacheKey (#10212) 2022-11-11 10:50:07 +01:00
Alexander M. Turek
318af0a666 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Psalm 4.30.0, PHPStan 1.9.2 (#10213)
2022-11-11 10:16:45 +01:00
Alexander M. Turek
7e45ad935c Psalm 4.30.0, PHPStan 1.9.2 (#10213) 2022-11-10 22:29:50 +01:00
Willem Verspyck
90ececcc85 Allow "Expr\Func" as condition in join (#10202) 2022-11-10 14:43:40 +01:00
Simon Podlipsky
88b36e07e1 refactor: use list type in SchemaTool (#10199) 2022-11-10 14:22:22 +01:00
Grégoire Paris
a37c2cc05f Merge pull request #10206 from greg0ire/rename-variable
Use a more accurate name for $annotationName
2022-11-06 22:13:19 +01:00
Grégoire Paris
40b34b03c1 Use a more accurate name for $annotationName 2022-11-06 21:44:29 +01:00
Grégoire Paris
8d9ab72613 Merge pull request #10204 from greg0ire/rename-internal-methods
Rename internal methods
2022-11-06 21:26:20 +01:00
Grégoire Paris
12f0674b1a Deprecate AttributeDriver::$entityAnnotationClasses 2022-11-06 21:04:05 +01:00
Grégoire Paris
069206ba14 Refer to attributes in comments and variable names 2022-11-06 21:04:05 +01:00
Grégoire Paris
e8a4d2e91b Remove useless comment
Cannot tell what this ignores.
2022-11-06 21:04:05 +01:00
Grégoire Paris
284baf890e Improve phpdoc 2022-11-06 21:04:05 +01:00
Grégoire Paris
a1f9b28cdc Replace Annotations with Attributes in method names
These are internal, so it should be fine.
2022-11-06 21:04:04 +01:00
Grégoire Paris
2b7485af97 Merge pull request #10205 from greg0ire/avoid-references-to-annotations
Avoid references to annotations
2022-11-06 20:56:45 +01:00
Grégoire Paris
edb6332359 Avoid $annotation as a parameter name 2022-11-06 14:58:38 +01:00
Grégoire Paris
48c1eef1b8 Migrate comments to attributes 2022-11-06 14:51:02 +01:00
Alexander M. Turek
5d88dc9be4 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  PHPStan 1.9.0 (#10200)
2022-11-04 13:08:38 +01:00
Alexander M. Turek
0b14c01b93 PHPStan 1.9.0 (#10200) 2022-11-03 21:04:02 +01:00
michnovka
c97f0a1078 Backport NonProxyLoadingEntityManager::refresh() signature change (#10197) 2022-11-02 16:49:13 +01:00
Alexander M. Turek
474f76fc8b Remove Doctrine\Persistence\ObjectManager::refresh from Psalm baseline 2022-11-02 00:15:00 +01:00
michnovka
25ce9b9101 Add lockMode to EntityManager#refresh() (#10040) 2022-11-01 23:59:11 +01:00
Alexander M. Turek
75340b68b2 Merge 2.13.x into 2.14.x (#10190) 2022-10-31 09:20:30 +01:00
Alexander M. Turek
543be3fe35 Deprecate the Annotation interface (#10178) 2022-10-26 21:51:46 +02:00
Alexander M. Turek
552d98d554 Bump CI to PHP 8.2 and latest database versions (#10180) 2022-10-26 15:12:52 +02:00
Alexander M. Turek
8f605c652a Remove reference to deprecated DriverChain from docs (#10179) 2022-10-26 15:09:12 +02:00
Alexander M. Turek
1edfa91714 Merge 2.13.x into 2.14.x (#10181) 2022-10-26 11:53:28 +02:00
Alexander M. Turek
75e42abfdf PHPStan 1.8.11 (#10182) 2022-10-26 11:36:22 +02:00
Romain Monteil
3133bf06c2 Add isMemberOf and isInstanceOf to Expr helper list (#10104)
* Add isMemberOf and isInstanceOf to Expr helper list

* Apply suggestions from code review

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-10-26 11:04:17 +02:00
Grégoire Paris
7cf4074d3a Migrate more references to annotations (#10176) 2022-10-26 10:42:42 +02:00
Jonny Eom
bb1deba510 Fix grammer in working-with-objects (#10120) 2022-10-26 10:39:05 +02:00
HypeMC
c828a3814b Automap events in AttachEntityListenersListener (#10122) 2022-10-26 10:36:06 +02:00
Grégoire Paris
a5553a0786 Adapt use statements to the code (#10174) 2022-10-25 23:25:36 +02:00
Grégoire Paris
cf91ce63d3 Merge pull request #10153 from greg0ire/address-dbal-deprecations
Address dbal deprecations
2022-10-24 08:53:38 +02:00
Alexander M. Turek
f3f453286f Deprecate EntityManager::create() (#9961) 2022-10-24 00:15:56 +02:00
Grégoire Paris
7cb96fcf0e Address deprecation of SchemaDiff::toSaveSql()
This implies deprecating a feature relying on that method.
2022-10-23 23:29:36 +02:00
Grégoire Paris
ac94d826dc Address deprecation of SchemaDiff::toSql()
The new method AbstractPlatform::getAlterSchemaSQL() should be preferred
when available.
2022-10-23 22:58:31 +02:00
Grégoire Paris
f33919d7d6 Merge pull request #10162 from greg0ire/stderr-for-humans
Use error style for notifications
2022-10-23 22:56:18 +02:00
Grégoire Paris
f256d996cc Use error style for notifications
stderr is not a great name for something that is not meant to be
processed (piped into) a program, but to be read by humans.
Most commands should use stderr, and some of them should partially use
stdout, typically when dumping SQL requests.
2022-10-23 21:51:12 +02:00
Grégoire Paris
d617323a48 Merge pull request #10161 from greg0ire/deprecate-mapping-drivers
Make the mapping driver deprecations more obvious
2022-10-23 10:30:43 +02:00
Alexander M. Turek
6b61e26238 Fix calls to AbstractSchemaManager::createSchema() (#10165) 2022-10-22 17:04:53 -07:00
Alexander M. Turek
edad800711 Merge 2.13.x into 2.14.x (#10164) 2022-10-23 01:19:54 +02:00
Alexander M. Turek
0b9c949590 Fix build with DBAL 3.5 (#10163) 2022-10-23 01:11:03 +02:00
Grégoire Paris
3ee7d96179 Adjust comments (#10160) 2022-10-22 15:34:10 +02:00
Grégoire Paris
fba05675b6 Deprecate methods related to the annotation driver 2022-10-22 15:23:57 +02:00
Grégoire Paris
8160e89c5a Use correct link 2022-10-22 15:05:19 +02:00
Grégoire Paris
a76b776802 Deprecate annotations 2022-10-22 14:54:12 +02:00
Grégoire Paris
ad1d1ca942 Remove trailing whitespace 2022-10-22 14:54:12 +02:00
Grégoire Paris
be835bb8e2 Merge remote-tracking branch 'origin/2.13.x' into 2.14.x 2022-10-21 21:28:17 +02:00
Grégoire Paris
9f926f04ba Merge pull request #10157 from greg0ire/followup-migrate-docs-to-attributes
Migrate more documentation towards attributes
2022-10-21 21:25:08 +02:00
Grégoire Paris
4e445feb6c Migrate more documentation towards attributes
The previous rework missed some details / left the documentation in an
inconsistent state. Searching for "annotation" case insensitively allows
to find discrepancies and forgotten things.
2022-10-21 12:31:10 +02:00
Grégoire Paris
d79e61f8d9 Remove wrong sentence 2022-10-21 12:31:10 +02:00
Simon Podlipsky
06eafd82ac Do not export phpstan stuff (#10154) 2022-10-19 13:36:12 +02:00
Alexander M. Turek
bac784c9ba Merge 2.13.x up into 2.14.x (#10149) 2022-10-17 23:19:27 +02:00
Grégoire Paris
5f4b76b88f Merge pull request #10126 from greg0ire/migrate-docs-to-attributes
Modernize documentation code
2022-10-17 23:11:33 +02:00
Grégoire Paris
794777b21f Modernize documentation code
- migrate to attributes;
- add helpful phpdoc annotations;
- use typed properties;
- add type declarations.

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-10-17 22:56:34 +02:00
Alexander M. Turek
119c378a3a Add CI jobs for SQLite3 driver (#10141) 2022-10-17 22:48:07 +02:00
Grégoire Paris
90bc6dc300 Merge pull request #10136 from greg0ire/trigger-sa-workflows-less
Stop triggering static analysis workflows on tests
2022-10-17 22:45:22 +02:00
Alexander M. Turek
1ad936a448 Fix type doc blocks in annotation classes (#10145) 2022-10-17 22:20:08 +02:00
Ondřej Mirtes
e93e8e0bdf Fix FieldMapping for generated key (#10144) 2022-10-17 15:37:06 +02:00
Alexander M. Turek
7e75807918 Merge 2.13.x into 2.14.x (#10139) 2022-10-17 10:14:22 +02:00
Grégoire Paris
bdf067b58a Stop triggering static analysis workflows on tests
In my opinion it is not great that we do not run static analysis tools on
tests, but since we do not, let us stop triggering extra jobs for no reason.
2022-10-15 23:59:57 +02:00
Grégoire Paris
f08b67f0cc Merge pull request #10135 from greg0ire/remove-extra-file
Remove file suffixed with singular
2022-10-15 11:59:05 +02:00
Grégoire Paris
5f8504b5cf Remove file suffixed with singular
It was wrongly preserved after a conflict that followed a rename.
2022-10-15 11:57:22 +02:00
Grégoire Paris
16e25656d9 Merge pull request #10134 from greg0ire/lighter-builds-💚🌍
Run only relevant workflows
2022-10-15 11:48:21 +02:00
Grégoire Paris
cacdc56b6e Run only relevant workflows
The downside of this is that we will have to tweak the settings so that
no job is required anymore.
The upside is that builds should be faster, and less resource-intensive.
2022-10-15 11:44:34 +02:00
Alexander M. Turek
90f82202a8 Merge 2.13.x into 2.14.x (#10129) 2022-10-13 15:21:22 +02:00
Alexander M. Turek
97aa5b37e6 Allow doctrine/event-manager 2 (#10123) 2022-10-13 13:15:37 +02:00
Alexander M. Turek
13d1c7b286 Psalm 4.29 (#10128) 2022-10-13 10:03:12 +02:00
Grégoire Paris
1a9f40c785 Address deprecation of Table::changeColumn() (#10121)
It is deprecated in favor of Table::modifyColumn().
2022-10-11 19:38:01 +02:00
Pierre du Plessis
06c77cebb5 Make code blocks consistent (#10103) 2022-10-10 23:31:20 +02:00
HypeMC
1ed0057276 Fix change set computation with enums (#10074)
* add failing testcase test enum Change sets

* Fix change set computation with enums

Co-authored-by: Olda Salek <mzk@mozektevidi.net>
2022-10-10 11:59:04 +02:00
Grégoire Paris
7ce9a6fe5c Merge pull request #10116 from greg0ire/address-dbal-deprecations
Address deprecations form DBAL
2022-10-10 08:42:54 +02:00
Grégoire Paris
8e062955d5 Address deprecations from DBAL
See https://github.com/doctrine/dbal/pull/5731
2022-10-10 08:42:21 +02:00
Alexander M. Turek
5b6f3cd598 PHPStan 1.8.8, Psalm 4.28.0 (#10115) 2022-10-09 23:31:52 +02:00
Grégoire Paris
38271d4aeb Merge pull request #10110 from davidromani/2.13.x
Fix deprecated trigger help comment
2022-10-08 22:42:56 +02:00
David Romaní
84213b9f05 fix deprecated trigger help comment 2022-10-07 18:03:42 +02:00
Grégoire Paris
0e65b0c3dc Merge pull request #10108 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-10-07 08:52:39 +02:00
Grégoire Paris
e750360bd5 Merge pull request #10101 from greg0ire/followup-9488
Assert that serialization leaves PersistentCollection usable
2022-10-07 08:37:17 +02:00
Alexander M. Turek
e14e9bebcc Merge pull request #10105 from greg0ire/backport-dbal-fixes
Backport DBAL-related fixes
2022-10-06 19:57:45 +02:00
Grégoire Paris
e8ac1169ad Bump CI workflows (#10106) 2022-10-06 16:57:00 +02:00
Grégoire Paris
9422260efd Specify precision for decimal columns
doctrine/dbal 4 no longer provides a default value for that column
option.
2022-10-06 11:32:28 +02:00
Grégoire Paris
d46512332c Address AbstractSchemaManager::createSchema() removal 2022-10-06 10:56:38 +02:00
Grégoire Paris
0d56ffc261 Address method rename
See https://github.com/doctrine/dbal/pull/5724
2022-10-06 10:46:22 +02:00
Grégoire Paris
dd8c7003b8 Assert that serialization leaves PersistentCollection usable
That feature is no longer covered since support for merging entities in
the entity manager was removed.
2022-10-06 10:40:06 +02:00
Grégoire Paris
9bec416bb0 Merge pull request #10100 from greg0ire/forward-compat-attributes
Forward compat attributes
2022-10-05 22:44:49 +02:00
Grégoire Paris
021722acc7 Remove ignored annotation
Making it a separate, valid annotation breaks the tests
2022-10-05 22:15:04 +02:00
Grégoire Paris
5a528bef5d Use short class name
It is more friendly with conversion to attributes
2022-10-05 22:00:44 +02:00
Grégoire Paris
5fbcb18334 Spell cities properly 2022-10-05 21:55:24 +02:00
Grégoire Paris
8280f41fa5 Merge pull request #10099 from greg0ire/fix-attribute-docs
Fix attribute reference
2022-10-05 21:48:46 +02:00
Grégoire Paris
d95d8d0a19 Fix broken links 2022-10-05 21:40:09 +02:00
Grégoire Paris
d36004f825 Remove trailing whitespace 2022-10-05 21:39:31 +02:00
Grégoire Paris
18366db578 Remove reference to JoinColumns
While that class can be an annotation, it cannot be an attribute because
it is not necessary when using attributes.

See https://github.com/doctrine/orm/issues/9986
2022-10-05 21:38:38 +02:00
Grégoire Paris
95c818928e Merge pull request #10098 from greg0ire/deprecate-annotations 2022-10-05 13:37:57 +02:00
Grégoire Paris
f27034880a Remove trailing whitespace 2022-10-05 12:24:53 +02:00
Grégoire Paris
3735822662 Deprecate annotation driver
No new project should use that driver.
2022-10-05 12:24:53 +02:00
Grégoire Paris
52f7ddc680 Use appropriate directive 2022-10-05 09:46:43 +02:00
Grégoire Paris
de32d8239f Merge pull request #10089 from greg0ire/remove-unneeded-checks
Document properties as possibly null
2022-10-04 23:28:01 +02:00
Grégoire Paris
1b5bef3d4d Merge pull request #10094 from doctrine/fix_doc_toc 2022-10-04 15:55:16 +02:00
Christophe Coevoet
880b622fe6 Fix heading levels for the embeddable tutorial 2022-10-04 14:13:44 +02:00
Grégoire Paris
397751ee65 Update Psalm baseline 2022-10-03 21:41:04 +02:00
Grégoire Paris
b0038eeea6 Document properties as possibly null
__sleep() does not list these properties as suposed to be serialized.
This means we have to assert that it is not in the many scenarios where
we resort to these properties. Introducing a private method allows us to
centralize the assertions.
2022-10-03 21:41:03 +02:00
Grégoire Paris
f06f9f843e Merge pull request #10093 from doctrine/2.13.x
Merge 2.13.x up in 2.14.x
2022-10-03 21:40:34 +02:00
Grégoire Paris
cbf141f7ed Add missing variable name in param phpdoc and switch to psalm-assert (#10092)
* Add missing variable name in param phpdoc

* Use psalm-assert instead of psalm-param

The parameter can in fact be any string, but if an exception is not
thrown, then it was a valid value.
2022-10-03 21:17:21 +02:00
Grégoire Paris
5d3fc62023 Merge pull request #10086 from franmomu/create_specific_event_classes
Create dedicated event argument classes
2022-10-02 21:49:09 +02:00
Grégoire Paris
154e7130f5 Merge pull request #10091 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-10-02 16:54:10 +02:00
Grégoire Paris
536bb4f678 Merge pull request #10090 from greg0ire/update-psalm-baseline
Update Psalm baseline
2022-10-02 16:23:14 +02:00
Grégoire Paris
3f2f42277e Update Psalm baseline 2022-10-02 16:02:57 +02:00
Fran Moreno
99f044cbc7 Deprecate LifecycleEventArgs 2022-10-01 14:39:31 +02:00
Fran Moreno
e8ca7b4abf Add dedicated classes for events 2022-10-01 14:39:31 +02:00
Grégoire Paris
b05fb96ad3 Merge pull request #10070 from greg0ire/preview-coll-2
Add support for doctrine/collection 2
2022-09-29 23:30:59 +02:00
Grégoire Paris
bb020320ca Allow collections 2 2022-09-29 23:08:43 +02:00
Grégoire Paris
1e0ac8899c Merge pull request #10079 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-09-29 23:07:20 +02:00
Grégoire Paris
757d950128 Merge pull request #10080 from greg0ire/add-missing-template-annotation
Address changes from doctrine/collections 1.8.0
2022-09-29 22:58:03 +02:00
Grégoire Paris
f07840b10c Address changes from doctrine/collections 1.8.0
Not quite sure why this annotation is not inherited.
2022-09-29 17:07:57 +02:00
Grégoire Paris
6e8afeeb60 Merge pull request #10072 from greg0ire/fix-return-type 2022-09-27 13:50:49 +02:00
Grégoire Paris
9130b27aca Remove return type override
In the parent class, all 3 methods are documented to return mixed.
This was not forward compatible with the addition of return types.
2022-09-27 13:41:09 +02:00
Grégoire Paris
2e7c2bb385 Merge pull request #10058 from HypeMC/enum-with-query-builder-fix
Fix using enums with the QueryBuilder
2022-09-23 22:08:15 +02:00
HypeMC
d69a0fa2cf Fix using enums with the QueryBuilder 2022-09-22 22:39:52 +02:00
Grégoire Paris
4a04c8c2db Merge pull request #10055 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-09-22 15:49:21 +02:00
Grégoire Paris
a8b02fd70f Merge pull request #10054 from greg0ire/sa-fixes 2022-09-22 15:36:43 +02:00
Alexander M. Turek
60adc6b7d9 Fix CS 2022-09-22 12:06:40 +02:00
Alexander M. Turek
c65ff6651c Merge branch '2.13.x-enum-arrayhydration' into 2.13.x
* 2.13.x-enum-arrayhydration:
  Fix ArrayHydration of enums
2022-09-22 12:04:22 +02:00
Alexander M. Turek
5f29fcdea2 Revert "Fix EnumType not being hydrated with HYDRATE_ARRAY (#9995)"
This reverts commit bb3ce7e802.
2022-09-22 12:04:09 +02:00
Grégoire Paris
470e2ddd05 Merge pull request #10045 from nicolas-grekas/proxy-common-less 2022-09-22 11:29:02 +02:00
Nicolas Grekas
6ec5ab9145 Deprecate Doctrine\ORM\Proxy\Proxy and decouple a bit more from Doctrine\Common\Proxy 2022-09-22 09:56:30 +02:00
Grégoire Paris
2b8ac15813 Mark ClassMetadataInfo::sequenceGeneratorDefinition as nullable 2022-09-22 09:12:50 +02:00
Alexander M. Turek
86000d9c70 Merge 2.13.x into 2.14.x (#10051) 2022-09-22 08:41:04 +02:00
Grégoire Paris
6dd07e4c76 Merge pull request #9983 from VincentLanglet/discriminatorColumn
Add phpdoc for ClassMetadataInfo::discriminatorColumn property
2022-09-21 23:17:54 +02:00
Alexander M. Turek
328bf707cc Merge 2.13.x into 2.14.x (#10046) 2022-09-18 15:20:51 +02:00
Alexander M. Turek
0d043059b9 PHPStan 1.8.5, Psalm 4.27.0 (#10033) 2022-09-18 15:06:51 +02:00
Ilya Shashilov
bb3ce7e802 Fix EnumType not being hydrated with HYDRATE_ARRAY (#9995)
Co-authored-by: Ilya Shashilov <kvushiha@gmail.com>
2022-09-14 14:33:42 +02:00
Tomas
bc7e252f00 Fix ArrayHydration of enums 2022-09-12 17:01:40 +02:00
Carlos Buenosvinos
498da2ff98 "Strange" return lines in documentation of inheritance-mapping.rst (#10027) 2022-09-04 18:16:02 +02:00
Carlos Buenosvinos
73e1e42ab5 More strange break lines in inheritance-mapping.rst (#10028) 2022-09-03 21:40:53 +02:00
Alexander M. Turek
7a9037e9d7 Merge branch '2.13.x' into 2.14.x
* 2.13.x:
  Bump Ubuntu version and shared workflows (#10020)
  Fail gracefully if EM could not be constructed in tests (#10008)
2022-08-30 21:22:58 +02:00
Alexander M. Turek
5d11648767 Bump Ubuntu version and shared workflows (#10020) 2022-08-30 21:10:38 +02:00
Vincent Langlet
8d03f8f089 Make paginator covariant (#10002) 2022-08-30 13:43:14 +02:00
Alexander M. Turek
0ecac1b255 Fail gracefully if EM could not be constructed in tests (#10008) 2022-08-30 13:40:54 +02:00
Grégoire Paris
8dfe8b8782 Merge pull request #10010 from doctrine/2.13.x
Merge 2.13.x up into 2.14.x
2022-08-27 21:07:59 +02:00
Grégoire Paris
b2a4fac40b Merge pull request #10009 from greg0ire/cs-update
Upgrade to doctrine/coding-standard 10.0.0
2022-08-27 20:53:59 +02:00
Grégoire Paris
beeba93a53 Upgrade to doctrine/coding-standard 10.0.0 2022-08-27 19:04:47 +02:00
Alexander M. Turek
4c253f2403 Merge pull request #10006 from derrabus/fix/build
Fix build
2022-08-26 13:07:34 +02:00
Alexander M. Turek
46ec86557e Bump coding standard to 9.0.2 2022-08-26 12:27:20 +02:00
Alexander M. Turek
f287b74470 Fix tests for doctrine/common 3.4 2022-08-26 00:34:50 +02:00
Alexander M. Turek
12d086551e Fix static analysis errors for Collections 1.7 2022-08-26 00:09:37 +02:00
Alberto Acha
5283e1441c Fix type in docs (#9994) 2022-08-16 20:40:01 +02:00
Michael Olšavský
18be6d2218 Improve orphan removal documentation - recommend using cascade=persist (#9848)
* Improve orphanRemoval documentation

* Wording improvement

* Update docs/en/reference/working-with-associations.rst

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

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2022-08-09 21:39:43 +02:00
Vincent Langlet
2fda625dba Add phpdoc for discriminatorColumn 2022-08-08 22:34:18 +02:00
Alexander M. Turek
35c44a5667 Backport type fixes for EntityListenerResolver (#9977) 2022-08-08 11:00:16 +02:00
Fran Moreno
0215b6b9fb Undeprecate LifecycleEventArgs (#9980)
Deprecating this class means that users using SA tools have to
update their code specifying the ObjectManager implementation.

Instead of this, dedicated classes for each event should be
created before deprecating this class.
2022-08-08 10:59:03 +02:00
Fran Moreno
cc9272f53f Update documentation to not use deprecated method (#9979) 2022-08-08 07:46:05 +00:00
Alexander M. Turek
e3e7f3c209 Update branch metadata (#9971) 2022-08-07 19:56:19 +02:00
Alexander M. Turek
c9870a3d82 Remove calls to deprecated Type::getName() (#9972) 2022-08-07 19:55:23 +02:00
Alexander M. Turek
827cb0c10b Address DBAL 3.4 deprecations (#9969) 2022-08-07 18:11:43 +02:00
Vincent Langlet
4d19c0ea71 Improve phpdoc for ClassMetadataInfo (#9965) 2022-08-07 16:00:01 +00:00
Alexander M. Turek
17cfb944f2 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Fix build (#9964)
  fix: class normalisation test (#9966)
2022-08-07 17:39:22 +02:00
Alexander M. Turek
78d08584f1 Fix build (#9964) 2022-08-07 17:31:32 +02:00
Adrien Foulon
f7e202f3ed fix: class normalisation test (#9966) 2022-08-07 17:07:36 +02:00
Romain Canon
33f4db8405 Support native enum hydration when using NEW operator (#9936)
Using the `NEW` operator with the query builder now properly converts
scalar values to native enums inside data transfer objects.
2022-08-04 00:33:46 +02:00
Alexander M. Turek
fa63a395cc Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Update branch info in README and .doctrine-project.json (#9943)
2022-08-02 22:35:33 +02:00
Alexander M. Turek
2ec2c585b0 Deprecate QueryBuilder APIs exposing its internal state (#9945)
Co-authored-by: Sergei Morozov <morozov@tut.by>
2022-08-01 11:42:24 +02:00
Alexander M. Turek
c8025dc4f8 Update branch info in README and .doctrine-project.json (#9943) 2022-07-31 14:53:31 +02:00
Alexander M. Turek
cd95b2a9e5 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Psalm 4.25.0, PHPStan 1.8.2 (#9941)
  Use a more precise phpdoc for ClassMetadataInfo::versionField than mixed (#9937)
2022-07-28 19:38:58 +02:00
Alexander M. Turek
8bfe20073b Psalm 4.25.0, PHPStan 1.8.2 (#9941) 2022-07-28 19:35:26 +02:00
Grégoire Paris
38a9a1c795 Stop passing event manager to constructor (#9938)
Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-07-28 16:47:04 +00:00
Grégoire Paris
2ebe18a822 Merge pull request #9915 from nicolas-grekas/pub-em 2022-07-28 14:55:34 +02:00
Vincent Langlet
9b37541b3b Use a more precise phpdoc for ClassMetadataInfo::versionField than mixed (#9937) 2022-07-27 23:23:43 +02:00
Nicolas Grekas
518d7f2ef1 Make EntityManager @final and its constructor public 2022-07-27 17:15:40 +02:00
Alexander M. Turek
7684cea8ef Add helper function TreeWalkerAdapter::getMetadataForDqlAlias() (#9932) 2022-07-25 20:54:31 +02:00
Alexander M. Turek
5085dbe94b Merge 2.12.x into 2.13.x (#9931) 2022-07-25 18:49:29 +02:00
Alexander M. Turek
6c64bc6067 Simplify LanguageRecognitionTest (#9930) 2022-07-25 16:14:07 +02:00
Grégoire Paris
f5246bdedd Merge pull request #9927 from rdey/patch-1
GH9335: Fix for bug with objects as foreign keys
2022-07-24 15:21:28 +02:00
Louise Zetterlund
705dc6fbda test/added test for foreign keys with custom id object types 2022-07-22 18:41:35 +02:00
Alexander M. Turek
faedb90ffa Widen types for DiscriminatorMap (#9922)
* Allow integers as keys for DiscriminatorMap

* Widen types for DiscriminatorMap
2022-07-21 10:19:42 +02:00
Grégoire Paris
2da28703e3 Merge pull request #9903 from glaszig/fix/dump-sql
schema tool: remove useless text from --dump-sql output
2022-07-19 23:13:51 +02:00
glaszig
20cec8ed79 schema tool: remove useless text from --dump-sql output
the description and semantics of the `--dump-sql` switch
indicate and sql dump. without that useless line

  The following SQL statements will be executed:

the output can actually be used to generate a plain
dump.sql file that can be fed into sql command-
consuming programs.

resolves #8263 and #7186.
2022-07-19 19:33:48 +00:00
Grégoire Paris
c125a856d0 Merge pull request #9914 from greg0ire/fix-build
Avoid supportsCreateDropDatabase()
2022-07-18 23:00:38 +02:00
Grégoire Paris
d7db596cb4 Avoid supportsCreateDropDatabase()
It has been deprecated.
2022-07-18 22:42:13 +02:00
Grégoire Paris
3a9aa5b8c6 Merge pull request #9910 from doctrine/2.12.x
Merge 2.12.x up into 2.13.x
2022-07-18 21:31:50 +02:00
Grégoire Paris
99d9c46bde Add tests for SQL output feature (#9907)
It is not covered yet, and that makes contributions to these commands
hard.
2022-07-18 21:28:17 +02:00
Grégoire Paris
61d405162f Merge pull request #9906 from franmomu/deprecate_lifecycleevent
Deprecate `LifecycleEventArgs`
2022-07-17 17:35:37 +02:00
Fran Moreno
b0f15e070d Deprecate LifecycleEventArgs
Use LifecycleEventArgs from doctrine/persistence instead.
2022-07-17 12:06:10 +02:00
Grégoire Paris
fbb7e24594 Merge pull request #9895 from greg0ire/avoid-sql-assertions
Avoid SQL assertions
2022-07-14 19:09:32 +02:00
Grégoire Paris
888a4a8eff Avoid SQL assertions
doctrine/dbal is the component responsible for generating the queries.
Let us make the test suite more robust by asserting that things work
from a functional point of view.
2022-07-12 08:01:19 +02:00
Grégoire Paris
48b4f63f61 Merge pull request #9893 from greg0ire/2.13.x
Merge 2.12.x up into 2.13.x
2022-07-10 23:18:39 +02:00
Grégoire Paris
4a62b661a5 Merge remote-tracking branch 'origin/2.12.x' into 2.13.x 2022-07-10 23:07:44 +02:00
Grégoire Paris
ab4844b82a Merge pull request #9892 from greg0ire/address-array-object-type-deprecation
Address array object type deprecation
2022-07-10 23:05:34 +02:00
Grégoire Paris
00989d6671 Remove SerializationModel from generic model set
It contains fields with deprecated types.
2022-07-10 12:23:05 +02:00
Grégoire Paris
7ed0db0621 Document what we test in test method name 2022-07-10 11:23:22 +02:00
Grégoire Paris
d6dcfbd6f7 Use ::class notation 2022-07-10 11:23:21 +02:00
Grégoire Paris
baf6a394a1 Test invalid mapping file with boolean model
SerializationModel has a field with type array, and another with type
object. Both types are deprecated.
2022-07-10 11:22:46 +02:00
Alexander M. Turek
1538d70bb9 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  PHPStan 1.8.0 (#9887)
  Fix typo in AbstractQuery
  ObjectHydrator: defer initialization of potentially empty collections
  Migrate more usages of SchemaTool::createSchema()
  preUpdate: Add restriction that changed field needs to be in computed changeset (#9871)
2022-07-08 13:54:43 +02:00
Alexander M. Turek
291765e879 PHPStan 1.8.0 (#9887) 2022-07-08 13:53:03 +02:00
Grégoire Paris
f79ec43e70 Merge pull request #9880 from CarlSchwan/patch-1
Fix typo in AbstractQuery
2022-07-06 21:07:32 +02:00
Carl Schwan
306b5f9812 Fix typo in AbstractQuery 2022-07-06 14:06:42 +02:00
Grégoire Paris
68405f3e5b Merge pull request #9876 from franmomu/extend_event_manager_args
Change parent classes in some events
2022-07-04 19:21:56 +02:00
Grégoire Paris
83c1ad2f57 Merge pull request #9870 from popov-a-e/GH-9807
[GH-9807] Fix: initialize potentially empty collections at the hydration complete
2022-07-03 22:25:18 +02:00
Alex Popov
79447cbb18 ObjectHydrator: defer initialization of potentially empty collections
If ObjectHydrator faces an empty row to an uninitialized collection,
it initializes it, to prevent it from querying again (DDC-1526).
However, if that row is the first but not the only in the collection,
the next rows will be ignored, as the collection will be considered
"existing", and "existing" collections are only replaced if REFRESH hint
is present. To prevent it, we defer initialization to the end of the
hydration.

Fixes GH-9807
2022-07-03 13:25:34 +04:00
Fran Moreno
eea53397c5 Change parent classes
*FlushEventArgs classes should extend ManagerEventArgs from
doctrine/persistence to be able to use ManagerEventArgs for any
persistance implementation.

OnClearEventArgs should extend from OnClearEventArgs from
doctrine/persistence.
2022-07-02 14:27:36 +02:00
Grégoire Paris
3295ccfa25 Merge pull request #9874 from greg0ire/migrate-to-csfm
Migrate more usages of SchemaTool::createSchema()
2022-07-02 00:11:41 +02:00
Grégoire Paris
b1419ddc6c Migrate more usages of SchemaTool::createSchema()
When I introduced OrmFunctionalTestCase::createSchemaForModels(), I made
several wrong assumptions:
- the call is always wrapped in a try / catch;
- that try / catch is always typed with "Exception".

Because of that, I missed, many, many occurrences of
SchemaTool::createSchema().

I recently noticed that contributors kept using the
SchemaTool::createSchema() and figured not everything had been
migrated.

Migrating some of them did not result in something far better until I
also introduced similar methods for
SchemaTool::getUpdateSchemaSql() and SchemaTool::getSchemaFromMetadata().
2022-07-01 21:45:45 +02:00
Thomas Landauer
0ef08c5dfb preUpdate: Add restriction that changed field needs to be in computed changeset (#9871) 2022-06-28 23:44:23 +02:00
Alexander M. Turek
dc8ddfd3e6 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Psalm 4.24.0, PHPStan 1.7.15 (#9865)
  PHP CodeSniffer 3.7.1, PHPStan 1.7.14 (#9858)
2022-06-28 13:35:26 +02:00
Alexander M. Turek
278bf194ca Psalm 4.24.0, PHPStan 1.7.15 (#9865) 2022-06-28 10:41:20 +02:00
Alexander M. Turek
b9f2488c6c PHP CodeSniffer 3.7.1, PHPStan 1.7.14 (#9858) 2022-06-19 14:48:36 +02:00
Hans Mackowiak
b931a59ebc Deprecate omitting the alias in QueryBuilder (#9765)
… methods update() and delete()

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-06-17 10:33:11 +02:00
Alexander M. Turek
d15eef9051 Merge release 2.12.3 into 2.13.x (#9853) 2022-06-17 10:22:16 +02:00
Alexander M. Turek
c05e1709e9 Run tests on PHP 8.2 (#9840) 2022-06-16 15:42:23 +02:00
Alexander M. Turek
6e31758c7b PHPStan 1.7.13 (#9844) 2022-06-15 11:11:24 +02:00
Alexander M. Turek
eff540a996 Flip conditional extension of legacy AnnotationDriver class (#9843) 2022-06-13 20:10:37 +02:00
Alexander M. Turek
33d74e2e48 PHP CodeSniffer 3.7 (#9842) 2022-06-13 19:19:15 +02:00
bartholdbos
09ff36cda0 Make Reflection available to ConvertMappingCommand (#9619) 2022-06-13 17:30:08 +02:00
Grégoire Paris
e30426cbc0 Merge pull request #9841 from derrabus/bugfix/dynamic-property
Add missing property declaration
2022-06-12 16:55:59 +02:00
Alexander M. Turek
e9135b86e0 Add missing property declaration 2022-06-12 14:25:39 +02:00
Grégoire Paris
5ccb59fa02 Merge pull request #9839 from morozov/list-tables
Use proper API for introspection of tables
2022-06-11 22:41:41 +02:00
Sergei Morozov
2e927970ca Use proper API for introspection of tables 2022-06-11 12:13:25 -07:00
Grégoire Paris
0366a5796f Merge pull request #9837 from greg0ire/address-getdbplatform-deprecation
Address deprecation of getDatabasePlatform()
2022-06-10 20:14:06 +02:00
Grégoire Paris
93f7e78a14 Address deprecation of getDatabasePlatform() 2022-06-10 19:57:50 +02:00
Grégoire Paris
d99e64c05e Merge pull request #9833 from greg0ire/deprecate-sequence-based-ig 2022-06-10 10:09:33 +02:00
Grégoire Paris
9efeefb913 Merge pull request #9826 from greg0ire/improve-phpdoc-configuration
Improve phpdoc for Configuration
2022-06-09 23:53:12 +02:00
Grégoire Paris
3f8430459c Deprecate reliance on sequence-emulated identity columns
Sequence-based identity values have been deprecated.
2022-06-09 23:46:50 +02:00
Grégoire Paris
5f12b8f7de Remove uneeded rule form baseline 2022-06-09 08:13:54 +02:00
Grégoire Paris
f949b9d212 Improve phpdoc for Configuration 2022-06-09 08:09:41 +02:00
Grégoire Paris
2bc0be6fa9 Merge remote-tracking branch 'origin/2.12.x' into 2.13.x 2022-06-09 07:47:32 +02:00
Grégoire Paris
3dc5581294 Merge pull request #9818 from greg0ire/fix-wrong-type-config
Document missing possible types
2022-06-09 07:23:43 +02:00
Grégoire Paris
7bf2c4c8d1 Merge pull request #9823 from greg0ire/fix-build 2022-06-08 14:39:31 +02:00
Grégoire Paris
c81776ad12 Backport fixes from upstream branch
Not all of 01fb82b497 was ported, only
what is necessary to fix the build.
2022-06-08 13:26:35 +02:00
Grégoire Paris
d9c6f86627 Document missing possible types 2022-06-04 18:16:35 +02:00
Alexander M. Turek
ddede4064c Merge 2.12.x into 2.13.x (#9811) 2022-06-03 13:22:41 +02:00
Alexander M. Turek
67d82cdf72 PHPStan 1.7.9 (#9812) 2022-06-03 13:11:19 +02:00
Alexander M. Turek
744f0b5983 Remove empty test file (#9805) 2022-06-03 07:53:13 +02:00
Grégoire Paris
1d02289481 Merge pull request #9809 from greg0ire/disallow-null-setFirstResult
Deprecate passing null to Query::setFirstResult()
2022-06-03 07:51:04 +02:00
Alexander M. Turek
4bd0f974ab Remove calls to deprecated MockBuilder::setMethods() (#9808) 2022-06-02 23:48:47 +02:00
Grégoire Paris
d0c582ca48 Deprecate passing null to Query::setFirstResult()
The argument is cast to an integer, so the user might as well pass 0
instead, and we can require an integer.
2022-06-02 22:29:01 +02:00
Alexander M. Turek
cc6cc26f18 Rename Abstract*Test to *TestCase (#9806) 2022-06-02 16:33:33 +02:00
wiseguy1394
768e2f3816 Add primary key on temp table (#9770)
* add primary key on temp table;fixes doctrine/orm#9768

* use all ID Columns in primary key
2022-06-02 16:08:22 +02:00
Grégoire Paris
deb5f49413 Merge pull request #9804 from greg0ire/2.13.x
Merge 2.12.x up into 2.13.x
2022-06-02 07:14:42 +02:00
Grégoire Paris
52ce39f595 Merge pull request #9801 from greg0ire/widen-types
Widen types
2022-06-02 07:13:58 +02:00
Grégoire Paris
f84ecb2842 Merge pull request #9794 from VincentLanglet/associationMapping
Add type for AssociationMapping
2022-06-01 23:37:00 +02:00
Grégoire Paris
b2fedaef9e Merge remote-tracking branch 'origin/2.12.x' into 2.13.x 2022-06-01 22:49:10 +02:00
Grégoire Paris
21976471a3 Fix wrong types (#9802) 2022-06-01 22:42:51 +02:00
Grégoire Paris
6fb88e1496 Widen return type
This type is so complex that it is not going to bring much value to the
consumer of this method. Let us widen it to mixed.
2022-06-01 19:56:25 +02:00
Sergei Morozov
3ac5f119aa Merge pull request #9799 from morozov/sqlite-fk
Prep work for enabling support for foreign keys on SQLite
2022-06-01 06:19:47 -07:00
Sergei Morozov
01fb82b497 Prep work for enabling support for foreign keys on SQLite 2022-05-30 18:45:43 -07:00
Alexander M. Turek
4f1072e1ac Add missing import (#9796) 2022-05-31 00:42:03 +02:00
Alexander M. Turek
a559563682 Deprecate calling setters without arguments (#9791) 2022-05-30 20:39:06 +02:00
Vincent Langlet
0f9cc194ae Update baseline 2022-05-29 20:27:26 +02:00
Vincent Langlet
2513a1e2b1 Fix 2022-05-29 20:16:12 +02:00
Vincent Langlet
4230214ced Add type for AssociationMapping 2022-05-29 13:17:04 +02:00
Alexander M. Turek
fb1f258736 Move duplicate fixture into dedicated file (#9789) 2022-05-27 15:08:21 +02:00
olegsuvorkov
aae8b43622 Update IdentifierFlattener.php
Fix for coding-standards / Coding Standards (8.1)
2022-05-27 15:35:23 +03:00
Alexander M. Turek
e66fbc434d MockTreeWalker should be an SqlWalker (#9790) 2022-05-27 00:15:30 +02:00
olegsuvorkov
3f4e9e397a Update IdentifierFlattener.php
Hello, I would like to make a small change.
The need arose when using \Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator in "symfony/doctrine-bridge" composite foreign keys
I'm sure these changes will not hurt performance
and allow other objects to be used as identifiers
2022-05-26 10:46:14 +03:00
Grégoire Paris
0f6f752887 Merge pull request #9777 from greg0ire/improve-phpdoc-abstract-query
Make phpdoc more precise for AbstractQuery
2022-05-24 20:42:40 +02:00
Grégoire Paris
c1dd1cfc2c Make phpdoc more precise 2022-05-24 20:42:10 +02:00
Grégoire Paris
3684d236f6 Deprecate setting fetch mode to random integers 2022-05-24 20:42:08 +02:00
Alexander M. Turek
bba6c696f5 Prepare split of output walkers and tree walkers (#9786) 2022-05-24 18:34:40 +00:00
Alexander M. Turek
e02e6f481b Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  PHPStan 1.7.0 (#9785)
2022-05-24 00:43:35 +02:00
Alexander M. Turek
48e4e333c7 PHPStan 1.7.0 (#9785) 2022-05-24 00:41:57 +02:00
Grégoire Paris
507bc514ce Merge pull request #9784 from greg0ire/deprecate-no-op
Deprecate passing null to Query::setDQL()
2022-05-23 22:31:50 +02:00
Grégoire Paris
1ae5de5409 Deprecate passing null to Query::setDQL()
It is a no-op.
2022-05-23 22:11:16 +02:00
Alexander M. Turek
82508956fe Kill call_user_func(_array) (#9780) 2022-05-23 16:28:32 +02:00
Alexander M. Turek
a131878814 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Fix wrong types for AbstractQuery and child classes (#9774)
  Document callable as possible
  Add use statement (#9769)
2022-05-23 11:29:26 +02:00
Grégoire Paris
1f63389065 Fix wrong types for AbstractQuery and child classes (#9774)
* Remove comment about BC

I do not think we actually want to force our users to build an array
collection when they want to use setParameters().

* Make phpdoc more accurate
2022-05-23 11:26:19 +02:00
Grégoire Paris
359dd4ecfb Merge pull request #9779 from greg0ire/fix-config-phpdoc 2022-05-23 11:18:58 +02:00
Grégoire Paris
a0697c9aff Document callable as possible
Custom string functions can either be a class string or a callable
returning the function.
2022-05-23 11:05:16 +02:00
Grégoire Paris
5601c2ce4b Merge pull request #9775 from greg0ire/no-override
Remove override phpdoc tag
2022-05-23 07:48:01 +02:00
Grégoire Paris
1141fe106f Remove override phpdoc tag
Given how little occurrences there are, signalling method overrides with
this tag is probably not something we do everywhere. Besides, it does
not seem to be standard.

See https://docs.phpdoc.org/3.0/guide/references/phpdoc/tags/index.html#tag-reference
2022-05-22 16:28:41 +02:00
Grégoire Paris
8f7701279d Add use statement (#9769)
We are supposed to use the driver from doctrine/persistence, and not the
deprecated one from this package.
2022-05-19 13:16:51 +02:00
Grégoire Paris
779f9c36fa Merge pull request #9766 from greg0ire/non-nullable-arg-ns
Document future argument better
2022-05-18 08:00:17 +02:00
Grégoire Paris
0908f92629 Document future argument better
That argument is always provided, so the tests should provide it and the
commented out argument should reflect the future.
2022-05-17 12:09:31 +02:00
Grégoire Paris
24badd60fb Merge pull request #9761 from greg0ire/fix-phpdoc-ns
Fix phpdoc and tests for NamingStrategy
2022-05-16 22:00:41 +02:00
Sergei Morozov
f2d794f8bc Merge pull request #9762 from morozov/schema-manager-database-platform
Do not call AbstractSchemaManager::getDatabasePlatform()
2022-05-16 08:31:45 -07:00
Sergei Morozov
7311f77dfe Do not call AbstractSchemaManager::getDatabasePlatform() 2022-05-15 19:25:51 -07:00
Grégoire Paris
16afa45abf Make tests more realistic
These tests were using the fact that some arguments of some methods of
the naming strategy interface are optional or nullable for now to avoid
providing some. In practice, these arguments are always provided, and
that should also be the case in tests.
2022-05-14 17:31:45 +02:00
Grégoire Paris
8b4d25e94f Handle self-refencing entities
When computing a foreign key column name, the referenced column name
may be null in the case of a self referencing entity with join columns
defined in the mapping.
2022-05-14 16:56:19 +02:00
Grégoire Paris
70087782e8 Merge pull request #9756 from greg0ire/more-precise-phpdoc-ns
Document types as they are passed
2022-05-12 09:05:51 +02:00
Grégoire Paris
dbc5a818e0 Document types as they are passed
Some arguments have been added afterwards which was a BC break for
implementing classes. I do not think they should have been introduced as
optional.
2022-05-11 21:36:44 +02:00
Alexander M. Turek
31a9c9c49b Update Psalm baseline (#9751) 2022-05-10 16:00:54 +02:00
Alexander M. Turek
125afb8e39 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Omit version number in README (#9749)
2022-05-10 15:08:24 +02:00
Grégoire Paris
45e196eb57 Omit version number in README (#9749) 2022-05-10 09:09:20 +02:00
Grégoire Paris
2c30fe6e5b Merge pull request #9748 from doctrine/2.12.x
Merge 2.12.x up into 2.13.x
2022-05-10 08:21:34 +02:00
Grégoire Paris
6757bdf8c6 Deprecate omitting second argument to joinColumnName() (#9747)
* fix headings

* Deprecate omitting second argument to joinColumnName()
2022-05-10 00:37:44 +02:00
Grégoire Paris
eed20ff4dd Better phpdoc tests (#9746)
* Fix inaccurate and imprecise phpdoc

* Remove extra argument

The method signature does not specify it, and it's always set to null.
It looks like this test and its data provider were copy/pasted from the
previous one.

* Specify what concrete class is passed

This is important as the signature of the concrete classes don't
necessarily match the one of the interface. Here, an extra argument that
is only defined in the classes is used.
2022-05-10 00:32:30 +02:00
Sergei Morozov
636712a928 Merge pull request #9737 from morozov/dbal-4-compatibility
Improve compatibility with DBAL 4 for MySQL, MariaDB and PostgreSQL
2022-05-07 07:42:14 -07:00
Sergei Morozov
0aa91c7140 Pass sequence name to AbstractPlatform::getDropSequenceSQL()
See https://github.com/doctrine/dbal/pull/4797
2022-05-06 19:15:06 -07:00
Sergei Morozov
c2f3831b85 Specify length for string columns
See https://github.com/doctrine/dbal/pull/3586
2022-05-06 19:15:06 -07:00
Sergei Morozov
2af52f6a18 Inherit parent column length regardless of the type
See https://github.com/doctrine/dbal/pull/3586
2022-05-06 19:15:05 -07:00
Sergei Morozov
0a79ddf344 Cast column length to int in XML annotation driver
See https://github.com/doctrine/dbal/pull/3511
2022-05-06 19:15:05 -07:00
Sergei Morozov
165c8bd6dd Do not use AbstractSchemaManager::dropAndCreateTable()
See https://github.com/doctrine/dbal/pull/4933
2022-05-06 19:15:03 -07:00
Alexander M. Turek
07ee555279 Exclude /ci from distribution packages (#9732) 2022-05-06 13:07:36 +02:00
Sergei Morozov
e6bda4afda Merge pull request #9730 from morozov/dbal-4-compatibility
Forward compatibility with DBAL 4
2022-05-05 14:06:25 -07:00
Sergei Morozov
51b4e02873 Obtain database platform from the connection, not from the driver
See https://github.com/doctrine/dbal/pull/4764
2022-05-05 11:30:36 -07:00
Sergei Morozov
1915dcd1e8 Use zero as the default query offset
See https://github.com/doctrine/dbal/pull/3574
2022-05-05 11:30:35 -07:00
Sergei Morozov
480d99b107 Use getStringTypeDeclarationSQL() instead of getVarcharTypeDeclarationSQL()
See https://github.com/doctrine/dbal/pull/3586
2022-05-05 11:30:35 -07:00
Sergei Morozov
c6661caaed Do not extend a type with a different PHP return type
See https://github.com/doctrine/dbal/pull/5043
2022-05-05 11:30:34 -07:00
Sergei Morozov
9e27370f15 Drop and create test database manually
See https://github.com/doctrine/dbal/pull/4933
2022-05-05 11:30:32 -07:00
Sergei Morozov
1a3fbcb145 Lookup type name in the registry
See https://github.com/doctrine/dbal/pull/5208
2022-05-05 09:32:38 -07:00
Sergei Morozov
c950e72628 Do not use null column definition 2022-05-05 09:32:37 -07:00
Alexander M. Turek
05560f260c Merge release 2.12.2 into 2.13.x (#9725) 2022-05-03 02:15:35 +02:00
Alexander M. Turek
8291a7f09b Allow doctrine/deprecations 1.0 (#9723) 2022-05-02 21:10:07 +02:00
Ruud Kamphuis
d7d6b9d2c7 Allow setting column options like charset and collation everywhere (#9655)
This makes it possible to set custom options on the following:
* `JoinTable`
* `JoinColumn`
* `InverseJoinColumn`
2022-05-02 19:01:24 +02:00
Grégoire Paris
26e274e373 Merge pull request #9708 from michnovka/2.12.x-fix-psalm-repository 2022-05-02 15:26:47 +02:00
Alexander M. Turek
a02642e3e6 Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  Psalm 4.23, PHPStan 1.6.3 (#9718)
2022-05-02 11:09:12 +02:00
Alexander M. Turek
5209184a60 Psalm 4.23, PHPStan 1.6.3 (#9718) 2022-05-02 11:07:33 +02:00
Grégoire Paris
b4da0ece41 Merge pull request #9704 from greg0ire/reference-cmi-less-and-less
Reference ClassMetadataInfo less and less
2022-05-01 22:06:19 +02:00
Sergei Morozov
3980d58b80 Merge pull request #9710 from morozov/2.13.x
Merge 2.12.x into 2.13.x
2022-05-01 12:46:13 -07:00
Sergei Morozov
10cbb24649 Merge branch '2.12.x' into 2.13.x 2022-05-01 12:24:28 -07:00
Sergei Morozov
23f54885bc Merge pull request #9706 from morozov/cleanup-test-entity-manager
Remove unused OrmTestCase::getTestEntityManager() parameters
2022-05-01 11:43:07 -07:00
Sergei Morozov
7f29b576d8 Remove some ConnectionMock methods (#9707) 2022-05-01 17:52:10 +02:00
Tomas
a8425a5248 Fix psalm annotation 2022-05-01 16:40:44 +02:00
Pierre B
86ce0e5e35 Update ClassMetadataInfo::table definition (#9703)
Everything except the name key might be undefined when accessing to this public property, for instance in a LoadMetadataEvent

Co-authored-by: Pierre Bourdet <pbourdet@worldia.com>
2022-05-01 09:40:00 +02:00
Sergei Morozov
39fd5f4d46 Remove unused OrmTestCase::getTestEntityManager() parameters 2022-04-30 12:35:05 -07:00
Grégoire Paris
476a02075f Deprecate classes and methods removed in 3.0 2022-04-30 19:47:20 +02:00
Grégoire Paris
98e10906f8 Change class metadata type declarations
There is a guarantee in the call sites that we are only passing
ClassMetadata instances.
2022-04-30 19:47:20 +02:00
Grégoire Paris
7241b4d2e0 Reference constants from ClassMetadata 2022-04-30 19:47:20 +02:00
Grégoire Paris
b8db858784 Deprecate not passing ClassMetadata instances 2022-04-30 19:47:20 +02:00
Thomas Landauer
a9309d748b Add missing use statement (#9699) 2022-04-30 08:04:44 +02:00
Grégoire Paris
fe09af6df1 Merge pull request #9701 from doctrine/2.11.x
2.11.x
2022-04-29 22:45:58 +02:00
Grégoire Paris
ed50e3d967 Merge pull request #9698 from ThomasLandauer/patch-8 2022-04-29 16:33:49 +02:00
Thomas Landauer
1d59e46245 use valid link syntax 2022-04-29 16:25:10 +02:00
Grégoire Paris
d8f3198ef8 Merge pull request #9693 from doctrine/2.12.x
Merge 2.12.x up into 2.13.x
2022-04-29 08:13:20 +02:00
Grégoire Paris
a0a0b0e476 Merge pull request #9692 from greg0ire/reference-cmi-even-less
Use ClassMetadata over ClassMetadataInfo in tests
2022-04-28 23:07:56 +02:00
Grégoire Paris
0078a67786 Use ClassMetadata over ClassMetadataInfo in tests
ClassMetadataInfo is deprecated in favor of ClassMetadata.
2022-04-28 21:40:23 +02:00
Grégoire Paris
38d1124be9 Merge pull request #9691 from greg0ire/reference-cmi-less
Reference ClassMetadaInfo less
2022-04-28 07:58:51 +02:00
Grégoire Paris
e9d3c218ef Remove explanation about inexistent distinction
ClassMetadataInfo used to be useful during entity generation, because it
allowed the entity not to exist. We no longer do entity generation, and
even if we did, the reflection methods have been moved to
ClassMetadataInfo as of 76e4f5a80b .
2022-04-27 23:28:58 +02:00
Grégoire Paris
6d2ca8fe40 Address mapping driver extraction
This documentation must be very old because this is no longer valid as
of e9e36dcf32 . The interface and abstract
file driver have since then been moved to doctrine/common, and the to
doctrine/persistence.
2022-04-27 23:28:43 +02:00
Grégoire Paris
a06011daf3 Refer to ClassMetadata instead of ClassMetadataInfo
Although properties and methods are currently located in
ClassMetadataInfo, it is better to refer to ClassMetadata as the former
is deprecated in favor of the latter.
2022-04-27 23:28:40 +02:00
Alexander M. Turek
825e9641fd Merge branch '2.12.x' into 2.13.x
* 2.12.x:
  PHPStan 1.6.1 (#9688)
  Drop SymfonyStyle[listing] for sqls (#9679)
2022-04-27 09:53:50 +02:00
Alexander M. Turek
0846b8b102 PHPStan 1.6.1 (#9688) 2022-04-26 23:52:07 +02:00
Simon Podlipsky
1dd2b44982 Drop SymfonyStyle[listing] for sqls (#9679)
This was super annoying as UpdateCommand printed sqls prefixed with `*` so it was not possible to copy statements anymore without manually removing those asterisks.

This removes prefixing sqls and makes it consistent with Create and Drop commands.
2022-04-26 15:33:18 +02:00
Alexander M. Turek
5fbe5ebef4 Merge 2.12.x into 2.13.x (#9684) 2022-04-26 11:32:14 +02:00
Alexander M. Turek
d9508e97df Remove dynamic property declarations (#9683) 2022-04-26 11:10:50 +02:00
Alexander M. Turek
534ed9c3c2 PHPStan 1.6.0 (#9682) 2022-04-26 11:01:11 +02:00
Grégoire Paris
f4585b954f Merge pull request #6728 from greg0ire/validate_xml_against_xsd
Validate XML mapping against XSD file
2022-04-25 23:04:26 +02:00
Grégoire Paris
ab3a255440 Validate XML mapping against XSD file
Co-Authored-By: Axel Venet <avenet@wamiz.com>
Co-authored-by: Luís Cobucci <lcobucci@gmail.com>
2022-04-25 22:55:00 +02:00
Grégoire Paris
a552df66a9 Merge pull request #9677 from greg0ire/assert-drivers-are-orm-specific
Document ORM drivers only really load ORM metadata
2022-04-24 20:55:13 +02:00
Grégoire Paris
85238d4d98 Document ORM drivers only really load ORM metadata 2022-04-24 20:05:37 +02:00
Fran Moreno
b7e9dd023c Fix HydrationException::invalidDiscriminatorValue parameter type (#9676) 2022-04-24 19:32:57 +02:00
Fran Moreno
1ac05f5e4e Fix type on ClassMetadata discriminatorMap (#9675) 2022-04-24 17:52:28 +02:00
Alexander M. Turek
2e4a872272 Conditionally extend the old AnnotationDriver class (#9671) 2022-04-22 19:46:03 +02:00
Alexander M. Turek
d550364431 Deprecate the doctrine binary (#9661) 2022-04-19 20:34:28 +02:00
Alexander M. Turek
5b2bf9d74c Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  ScalarColumnHydrator: prevent early-bail on falsy values (#9663)
2022-04-19 11:27:11 +02:00
Mitch
4af1aa3177 ScalarColumnHydrator: prevent early-bail on falsy values (#9663)
* add failing test for issue #9230

* ScalarColumnHydrator: prevent early-bail on falsy values, fix #9230

Co-authored-by: Mickael GOETZ <contact@mickael-goetz.com>
2022-04-19 09:01:33 +00:00
michnovka
2fe40679f4 Fix enum hydration when fetching partial results (#9657) 2022-04-16 20:49:28 +02:00
Alexander M. Turek
7029965d3a Indicate support for doctrine/persistence 3 (#9656) 2022-04-15 13:00:03 +02:00
michnovka
7e49c70320 Fix tests for enum ID hydration (#9658) 2022-04-13 12:58:20 +02:00
Grégoire Paris
f7fe5ad1bb Merge pull request #9654 from greg0ire/revert-9636
Revert "Use charset/collation from column or table default when creatng relations (#9636)"
2022-04-12 07:19:51 +02:00
Grégoire Paris
035c52ce3c Revert "Use charset/collation from column or table default when creating relations (#9636)"
This reverts commit 03f4468be2.
The inferring process seems fragile and MySQL-specific. The ORM might
not be the correct place to fix this issue (if it needs to be fixed at
all).
2022-04-11 20:26:17 +02:00
michnovka
7e7e38b60e Fix test file/class names (#9649) 2022-04-11 12:15:45 +02:00
Alexander M. Turek
36ab133e62 Leverage generic persistence event classes (#9633) 2022-04-11 11:58:42 +02:00
Alexander M. Turek
e13422ab5e Merge 2.11.x into 2.12.x (#9650)
* Fix composer install in contributing readme

People that contribute know how to use composer.

* Fix static analysis for Persistence 2.5 (#9648)

Co-authored-by: Ruud Kamphuis <ruudk@users.noreply.github.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2022-04-10 23:45:04 +02:00
Alexander M. Turek
f4d5283f70 Fix static analysis for Persistence 2.5 (#9648) 2022-04-10 23:31:12 +02:00
Grégoire Paris
fda79b8e21 Improve exception message (#9646)
In setups where you have many parameters, or do not even realise you are
using an entity, that additional piece of context can be helpful. The
parameter name is not always available where the old exception was
called though.
2022-04-10 23:08:52 +02:00
Alexander M. Turek
5a345b01dc Deprecate console helper (#9641) 2022-04-10 20:59:10 +02:00
Ruud Kamphuis
03f4468be2 Use charset/collation from column or table default when creating relations (#9636)
Fixes #6823
2022-04-10 14:34:21 +02:00
michnovka
a3d82f8e2f Support Enum IDs and search by Enum fields (#9629) 2022-04-09 23:40:41 +02:00
Grégoire Paris
976fe5bc0d Merge pull request #9639 from ruudk/patch-1
Fix composer install in contributing readme
2022-04-09 16:41:21 +02:00
Ruud Kamphuis
582b222b00 Fix composer install in contributing readme
People that contribute know how to use composer.
2022-04-09 15:29:45 +02:00
Alexander M. Turek
d9e8e839fe Deprecate custom ObjectRepository implementations (#9533) 2022-04-06 13:51:12 +02:00
Alexander M. Turek
e8472c8f1a Fix types on walkLiteral() and walkLikeExpression() (#9566) 2022-04-06 10:48:54 +02:00
Alexander M. Turek
deaab5133e Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  explicitly use the non-deprecated ORMException
2022-04-05 13:02:01 +02:00
Sander
cffe31fc9d Add support for array of enums (#9497)
* Add support for array of enums

This allows the use of 'array' and 'simple_array' in combination
with the enumType parameter.

* Reference is_array and array_map through a use statement nstead of global fallback

* Return the value of an array of enums correctly

* Add enum array mapping test

* Fix order of use parameters

* Fix return type docblock

* Apply phpcs feedback

* Fix static closure

* Add missing return type to static closure

* Add helper method for enum initialization to reduce code duplication

* Fix CS

* Replace mixed typehints with more specific ones

* Update docblock type hint to allow for array of string/int

* Fix types

* Fix types

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-04-05 01:29:40 +02:00
Alexander M. Turek
0e9c7533fb Fix types on ResultSetMapping (#9621) 2022-04-04 21:58:25 +02:00
Grégoire Paris
1ffb9152f7 Merge pull request #9623 from BenoitDuffez/dont-use-depecated-ormexception
explicitly use the non-deprecated ORMException
2022-04-02 11:52:48 +02:00
Benoit Duffez
51faa6ddb7 explicitly use the non-deprecated ORMException 2022-04-01 13:23:05 -07:00
Alexander M. Turek
18d6bc3757 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Remove "Description of" PHPDoc (#9611)
2022-03-31 00:14:34 +02:00
Alexander M. Turek
7c4ae58517 Support enums as default values (#9616) 2022-03-28 22:36:45 +02:00
Alexander M. Turek
05f8fcf836 Skip tests requiring ObjectManagerAware (#9612) 2022-03-28 13:50:45 +00:00
Alexander M. Turek
692c3e1b45 Remove "Description of" PHPDoc (#9611) 2022-03-28 13:47:30 +02:00
Alexander M. Turek
acff29fddd Update psalm.xml 2022-03-28 10:48:23 +02:00
Alexander M. Turek
58659f6c4f Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  PHPStan 1.5.0 (#9607)
  Remove Sphinx config
  Use correct syntax for external links
  Update XmlExporter.php - Type problem in php8.x (#9589)
  Ignore deprecation from Persistence
  Stands with Ukraine (#9567)
  Use internal links when self-referencing
  Link to docs for the stable version
2022-03-28 10:46:50 +02:00
Alexander M. Turek
e410180c6e PHPStan 1.5.0 (#9607) 2022-03-28 10:37:03 +02:00
Grégoire Paris
4476b05d59 Merge pull request #9608 from greg0ire/remove-python-config
Remove Sphinx config
2022-03-26 17:15:36 +01:00
Grégoire Paris
343b0ae576 Remove Sphinx config
I do not think this file is still useful, since AFAIK we are not using
Sphinx anymore. Besides, this is the only Doctrine project I could find
that still has that file. It was last updated 6 years ago.
2022-03-26 12:07:22 +01:00
Grégoire Paris
9952350c64 Merge pull request #9604 from greg0ire/improve-exception-message
Indicate what feature is deprecated
2022-03-24 08:46:03 +01:00
Grégoire Paris
3bc78caba9 Indicate what feature is deprecated 2022-03-23 18:39:33 +01:00
Grégoire Paris
0f1c9ec72a Merge pull request #9603 from greg0ire/int-mask-of 2022-03-22 14:18:14 +01:00
Grégoire Paris
80f65d6f77 Implement int-mask-of where appropriate
With Psalm, you can specify that an integer should be a bitmask of
constants. Doing so allows to make some types more precise.
2022-03-22 14:02:31 +01:00
Grégoire Paris
de69f60c6a Merge pull request #9598 from greg0ire/fix-event-table
Use correct syntax for external links
2022-03-20 19:32:10 +01:00
Grégoire Paris
2a653b05a0 Use correct syntax for external links
There is no leading underscore, and the trailing underscore should not
be forgotten.
2022-03-20 19:13:19 +01:00
Grégoire Paris
0f04a82857 Merge pull request #9595 from greg0ire/deprecate-more-ns-aliases
Deprecate more occurrences of namespace aliases
2022-03-20 14:34:16 +01:00
Grégoire Paris
17903346cf Deprecate more occurrences of namespace aliases 2022-03-20 14:26:13 +01:00
Alexander M. Turek
98b468da57 Fix type on SqlWalker::walkPathExpression() (#9565) 2022-03-20 13:42:41 +01:00
Grégoire Paris
bccb4c7bd9 Merge pull request #9592 from greg0ire/fix-persistence-compat
Deprecate or throw on namespace alias usage
2022-03-20 12:26:28 +01:00
Grégoire Paris
dc53628faf Deprecate or throw on namespace alias usage
This feature has been deprecated and removed in doctrine/persistence.
It was already deprecated in doctrine/orm for other APIs.
2022-03-20 11:44:42 +01:00
Grégoire Paris
21f339e6eb Merge pull request #9528 from greg0ire/get-rid-of-persistent-object
Implement forward compatibility with Persistence 3
2022-03-19 13:18:06 +01:00
Jan Záruba
c6831c6b07 Update XmlExporter.php - Type problem in php8.x (#9589)
Please see PHP interface SimpleXMLElement::addAttribute(string $name, string $value = null, string $namespace = null): void .... 
The $value must be string or null.
2022-03-19 13:03:28 +01:00
Grégoire Paris
33da4d84eb Merge pull request #9590 from greg0ire/fix-build
Ignore deprecation from Persistence
2022-03-18 22:56:08 +01:00
Grégoire Paris
08de12e962 Merge pull request #9580 from klammbueddel/bug/duplicate-object-in-nested-collections
Add test to reproduce #9579
2022-03-18 22:54:19 +01:00
Grégoire Paris
7c83373f1e Add specific CI jobs for Persistence 3 2022-03-18 22:25:47 +01:00
Grégoire Paris
021164fbe5 throw when attempting to use partial clearing 2022-03-18 22:21:59 +01:00
Grégoire Paris
b2d0c21fe0 Workaround the impossibility of unsetting metadata 2022-03-18 21:49:08 +01:00
Grégoire Paris
7391e2586a Mock ClassMetadata::getName()
It is supposed to return a string.
2022-03-18 21:49:08 +01:00
Grégoire Paris
3532ce9a25 Remove useless calls 2022-03-18 21:49:08 +01:00
Grégoire Paris
2c769acf8c Implement forward compatbility with Persistence 3 2022-03-18 21:49:08 +01:00
Grégoire Paris
c1b373b931 Ignore deprecation from Persistence
The deprecation is already addressed in the next minor branch.
2022-03-18 19:19:15 +01:00
Christian Bartels
61cb557b18 Check if association already contains object (#9579) 2022-03-18 11:00:33 +01:00
Maxime Veber
b6cff1aa1c Stands with Ukraine (#9567) 2022-03-18 10:32:03 +01:00
Grégoire Paris
4471ad9f6b Merge pull request #9587 from greg0ire/implement-colocated-driver 2022-03-16 10:54:06 +01:00
Grégoire Paris
cd57768b08 Implement colocated mapping driver
This allows us to decouple further from doctrine/annotations, and to fix
some static analysis issues.

The assumption being made here is that the abstract class we are no
longer extending is not used in type declarations and instanceof checks.
2022-03-15 12:42:27 +01:00
Grégoire Paris
d2206152bb Merge pull request #9585 from greg0ire/hunt-down-latest 2022-03-13 17:11:29 +01:00
Grégoire Paris
a34dc0a0e3 Use internal links when self-referencing
This should result in links with the current version of the docs.
2022-03-13 14:36:37 +01:00
Grégoire Paris
881a7b3b69 Link to docs for the stable version
When we do not know what version people intend to browse, it seems more
sensible to assume they want to see the docs for the stable version.
2022-03-13 14:35:15 +01:00
Alexander M. Turek
b64824addb Leverage MemcachedAdapter::isSupported() (#9578) 2022-03-10 23:37:36 +01:00
Alexander M. Turek
c7104c9471 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Baseline Psalm errors caused by DBAL 3.3.3 (#9577)
  Make sure MemcachedAdapter is supported before tring to use it (#9574)
  Fixing `:doc:` link (#9569)
  Adding PHP attributes (#9555)
  Remove reference to removed class
2022-03-09 17:20:17 +01:00
Alexander M. Turek
82bbb1dc4a Baseline Psalm errors caused by DBAL 3.3.3 (#9577) 2022-03-09 17:18:11 +01:00
flack
9c351e0444 Make sure MemcachedAdapter is supported before tring to use it (#9574) 2022-03-09 16:23:58 +01:00
Thomas Landauer
5ed5383338 Fixing :doc: link (#9569) 2022-03-08 22:31:56 +01:00
Thomas Landauer
eb1d54871b Adding PHP attributes (#9555)
Co-authored-by: Alexander M. Turek <me@derrabus.de>
Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2022-03-08 01:40:01 +01:00
Grégoire Paris
e148c838b0 Merge pull request #9563 from greg0ire/address-sqllogger-deprecation
Remove reference to removed class
2022-03-03 22:27:51 +01:00
Grégoire Paris
c73df2a7b4 Remove reference to removed class
EchoSQLLogger is deprecated in DBAL 2, and removed in DBAL 3.
2022-03-03 22:12:04 +01:00
Alexander M. Turek
bc6c6c9f0c Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Parser: SimpleArithmeticExpression should return ArithmeticTerm (#9557)
2022-03-03 19:55:19 +01:00
Loïc Vernet
89d0a6a67c validate schema command: allow to debug missing schema updates list (#9019) 2022-03-03 18:35:32 +00:00
Jan Barášek
38682e93db Parser: SimpleArithmeticExpression should return ArithmeticTerm (#9557) 2022-03-03 00:25:27 +01:00
Alexander M. Turek
1febeaca7f Document tree walker class strings (#9553) 2022-03-01 20:14:46 +01:00
Alexander M. Turek
229dcb082b Use literal types for JOIN_TYPE_* constants (#9552) 2022-03-01 15:10:51 +01:00
Grégoire Paris
3849aed6fb Merge pull request #9549 from derrabus/improvement/leverage-token-type
Leverage Lexer's Token type
2022-02-28 20:56:19 +01:00
Alexander M. Turek
f82db6a894 Leverage Lexer's Token type 2022-02-28 20:27:19 +01:00
Alexander M. Turek
a8a859cf5e Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Update baselines for Lexer 1.2.3 (#9546)
2022-02-28 14:11:53 +01:00
Alexander M. Turek
84df37de97 Update baselines for Lexer 1.2.3 (#9546) 2022-02-28 14:06:31 +01:00
Alexander M. Turek
7be96f64ab Document QueryComponent array shape (#9527) 2022-02-25 00:21:29 +01:00
Grégoire Paris
947935e4c9 Merge pull request #9541 from greg0ire/improve-templating 2022-02-24 20:25:13 +01:00
Grégoire Paris
40af1fcfc6 Improve templating
This is helpful for static analysis
2022-02-24 18:19:30 +01:00
Alexander M. Turek
021444b322 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Fix bug-#9536
2022-02-24 11:24:13 +01:00
Alexander M. Turek
ec7c637cf2 Un-deprecate the current proxy mechanism (#9532) 2022-02-24 11:17:05 +01:00
Grégoire Paris
0a0779c4a9 Remove unused methods 2022-02-22 20:26:18 +01:00
Grégoire Paris
856c3143f8 Merge pull request #9537 from kiler129/fix-bug-9536
Make error message suggestion accurate
2022-02-22 20:08:49 +01:00
kiler129
79f73a23f3 Fix bug-#9536
Wrong validation message is displayed when an incorrect bidirectional
bi-directional mapping is set up. When the owning side is configured
correctly and the target side is missing the back reference, the ORM
suggests adding inverseBy instead of mappedBy, with the field name
missing. This commit fixes this problem.
2022-02-22 12:05:35 -06:00
Grégoire Paris
a52d9880cc Merge pull request #9542 from doctrine/2.11.x
Merge 2.11.x up into 2.12.x
2022-02-22 18:11:25 +01:00
Grégoire Paris
4af912f712 Merge pull request #9539 from greg0ire/use-stable-dbal
Drop minor version number
2022-02-22 18:01:26 +01:00
Grégoire Paris
65f48e0ecd Drop minor version number
We should make it explicit that we mean to test with whatever is the
latest 3.x
2022-02-22 17:25:21 +01:00
Alexander M. Turek
08eaba44ca Fix more types on EntityRepository and FilterCollection (#9525) 2022-02-20 21:09:41 +01:00
Alexander M. Turek
05c35c398f Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Bring `FilterCollection` to a "clean" state after hash computation (#9523)
2022-02-20 14:19:47 +01:00
Matthias Pigulla
193c3abf0e Bring FilterCollection to a "clean" state after hash computation (#9523)
Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-02-20 13:09:05 +00:00
Alexander M. Turek
dac1875a79 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Make creating test models more straightforward
  Trigger the desired code path
  Fix syntax typo in attributes reference (#9513)
  Constructor-Argument "options" has the same type as the associated property. (#9501)
2022-02-20 11:52:36 +01:00
Grégoire Paris
5b8263e8fb Merge pull request #9526 from greg0ire/better-model-setup
Make creating test models more straightforward and revert to swallowing exceptions
2022-02-20 09:35:21 +01:00
Grégoire Paris
26e85b8c88 Make creating test models more straightforward
In https://github.com/doctrine/orm/pull/8962, I established that
swallowing exceptions while creating model was bad because it could hide
other helpful exceptions.
As it turns out however, swallowing exceptions is really the way to go
here, because of the performance implication of calling dropSchema(). It
is possible to catch a more precise exception as well, which should
preserve the benefits of not swallowing them.

It looks like I based my grep on the comment inside the catch and today,
I found many other occurrences of this pattern, without the easy to grep
comment.

I decided to fix them as well, but in a lazier way: one no longer has to
remember to call dropSchema in tearDown() now, it is automated.
2022-02-20 09:26:57 +01:00
Grégoire Paris
152c04c03d Merge pull request #9519 from lcobucci/fix-pagination-test
Trigger the desired code path
2022-02-16 09:24:32 +01:00
Luís Cobucci
12ab6fa43f Trigger the desired code path
Since v2.7.0 the ORM avoids using extra queries via the paginator
component when maximum results isn't set on the original query. With
that change, this test was not executing the code path that it was
expected to run.

This makes sure we trigger the forcing of custom DBAL types when
hydrating the identifiers, making sure we don't introduce bugs.

More info:
- Forcing DBAL type conversion: https://github.com/doctrine/orm/pull/7905
- Issue on optimisation: https://github.com/doctrine/orm/issues/7829
- PR on optimisation: https://github.com/doctrine/orm/pull/7863
- Minor BC-break docs: https://github.com/doctrine/orm/blob/2.11.x/UPGRADE.md#minor-bc-break-paginator-output-walkers-arent-be-called-anymore-on-sub-queries-for-queries-without-max-results
2022-02-15 22:59:09 +01:00
Alexander M. Turek
5a55772559 Document deprecation of AbstractCollectionPersister helpers (#9512) 2022-02-15 22:54:30 +01:00
Yann Rabiller
e8e61cbbd5 Fix syntax typo in attributes reference (#9513)
Curly brackets are the annotation way of declaring array. Probably a
mistake while copy pasting some examples from annotations.
2022-02-15 14:32:33 +00:00
Alexander M. Turek
d78fa52ad7 Replace TreeWalkerChainIterator with a generator (#9511) 2022-02-15 13:00:15 +01:00
Alexander M. Turek
4ddaa5fc20 Fix types on caches (#9507) 2022-02-13 22:50:21 +01:00
Tony Lemke
8f847cb5aa Constructor-Argument "options" has the same type as the associated property. (#9501) 2022-02-13 21:42:15 +01:00
Alexander M. Turek
d7abcb01bc Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Fix AbstractQuery::setParameter phpdoc (#9504)
2022-02-13 11:02:56 +01:00
David Maicher
599832cb81 Fix AbstractQuery::setParameter phpdoc (#9504)
* Fix AbstractQuery::setParameter phpdoc

* Fix AbstractQuery::setParameter phpdoc
2022-02-12 21:49:30 +01:00
Alexander M. Turek
8cff7dcdaf Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Added "false" value to $columnPrefix type declaration. (#9493)
2022-02-09 14:56:45 +01:00
Dmytro Hordinskyi
530f515556 Added "false" value to $columnPrefix type declaration. (#9493) 2022-02-09 09:40:16 +01:00
Alexander M. Turek
601728045c Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  PHPStan 1.4.6, Psalm 4.20.0 (#9491)
  Fix `#[DiscriminatorMap]` params (#9487)
  Run tests with stricter error handling (#9482)
2022-02-09 00:51:01 +01:00
Alexander M. Turek
b18cd893be Fix types on QueryBuilder (#9492) 2022-02-09 00:48:36 +01:00
Alexander M. Turek
21390a12b9 Fix types on EntityRepository (#9474) 2022-02-09 00:44:30 +01:00
Alexander M. Turek
182bcbae23 Avoid calling merge() (#9489) 2022-02-09 00:42:49 +01:00
Alexander M. Turek
1c55025b12 PHPStan 1.4.6, Psalm 4.20.0 (#9491) 2022-02-09 00:42:34 +01:00
Steve
0900d4bc97 Fix #[DiscriminatorMap] params (#9487)
Fix `#[DiscriminatorMap]` params
2022-02-08 08:35:46 +00:00
Alexander M. Turek
be2518d784 Run tests with stricter error handling (#9482) 2022-02-07 22:08:34 +00:00
Alexander M. Turek
978f687df9 Modernize strpos() calls (#9480) 2022-02-07 09:34:45 +01:00
Alexander M. Turek
fd1690431f Fix types on persisters (#9466) 2022-02-07 09:26:15 +01:00
Grégoire Paris
3cfcd4ad13 Merge pull request #9479 from derrabus/improvement/useless-catch
Remove useless catches
2022-02-06 16:07:47 +01:00
Alexander M. Turek
69b0b764e3 Rename DoctrineSetup to ORMSetup (#9481) 2022-02-06 15:22:58 +01:00
Alexander M. Turek
e11cef5fca Remove useless catches 2022-02-06 00:20:25 +01:00
Alexander M. Turek
395c02caf4 Deprecate methods removed in 3.0 (#9475) 2022-02-05 22:41:33 +01:00
Alexander M. Turek
0c4e739e94 Merge 2.11.x into 2.12.x (#9473) 2022-02-05 20:15:38 +01:00
Alexander M. Turek
7a72526e47 Skip tests related to PersistentObject if that class is missing (#9472) 2022-02-05 19:31:42 +01:00
Alexander M. Turek
bdd8883d12 Run Postgres 14 and MariaDB 10.6 in CI (#9470) 2022-02-05 19:28:13 +01:00
Alexander M. Turek
5f882b1cdd Check requirements for metadata drivers (#9459) 2022-02-01 19:19:40 +01:00
Alexander M. Turek
b3d849dd38 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  PDO is not a required extension (#9457)
  Check requirements for metadata drivers (#9452)
  Remove trailing underscore (#9446)
2022-02-01 14:16:15 +01:00
Alexander M. Turek
536b65f02b PDO is not a required extension (#9457) 2022-02-01 14:13:50 +01:00
Alexander M. Turek
103c42cdb7 Check requirements for metadata drivers (#9452) 2022-02-01 13:48:03 +01:00
Alexander M. Turek
aa1dd881d8 Support enums in findBy() calls (#9453) 2022-01-31 23:02:58 +01:00
Alexander M. Turek
92d27f2fea Streamline cache creation in tests (#9451) 2022-01-31 21:55:39 +01:00
Alexander M. Turek
f8de44c35f Document the new DoctrineSetup class (#9448) 2022-01-31 08:13:10 +01:00
Grégoire Paris
cdaf7b5308 Remove trailing underscore (#9446)
It looks like there was confusion between the syntax for external links
and the syntax for internal links, which does not mention underscores.
See https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-doc
versus https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#external-links
2022-01-30 23:01:35 +00:00
Alexander M. Turek
f81980e1fa Introduce DoctrineSetup as a replacement for Setup (#9443) 2022-01-30 22:38:57 +00:00
Alexander M. Turek
e9e54d8f65 Merge release 2.11.1 into 2.12.x (#9444) 2022-01-30 23:04:07 +01:00
Claudio Zizza
4b88ce787d Introduce __unserialize behaviour in docs (#9390)
* Introduce __unserialize behaviour in docs

* Mention deprecation of Serializable interface

* Add link to __unserialize method
2022-01-30 22:47:06 +01:00
Alexander M. Turek
04bfdf85de Merge 2.11.x up into 2.12.x (#9441) 2022-01-30 18:06:16 +01:00
Grégoire Paris
f9c3470a8d Adapt test logic to PHP and SQLite II (#9442)
In a88242ee6c, testDateSub() was modified
in order to satisfy different opinions to the question "What is now
minus one month", that has different answers for different pieces of
software on March 30th.

Today, we are January 30th, we need to do the same for testDateAdd().
Hopefully this is the last time we hear about this.
2022-01-30 17:48:10 +01:00
Grégoire Paris
c1b131b67e Merge pull request #9440 from sir-kain/php-8.1-ci
Added php 8.1 to CI
2022-01-30 09:55:04 +01:00
Grégoire Paris
16b82ea061 Use the identify generator strategy
It is a better default, and should fix tests for PostgreSQL
2022-01-29 11:33:13 +01:00
Waly
f8f370ace6 Added php 8.1 to CI 2022-01-28 22:55:25 +00:00
Alexander M. Turek
43f67c6164 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Psalm 4.19.0, PHPStan 1.4.3 (#9438)
  Ignore PHPUnit result cache everywhere (#9425)
2022-01-28 23:08:59 +01:00
Alexander M. Turek
d5c69fb73f Psalm 4.19.0, PHPStan 1.4.3 (#9438) 2022-01-28 21:54:10 +00:00
Alexander M. Turek
93f9eb7af2 Ignore PHPUnit result cache everywhere (#9425) 2022-01-24 12:35:44 +01:00
Alexander M. Turek
f5be4183ce Introduce assertQueryCount (#9423) 2022-01-24 09:39:48 +01:00
Alexander M. Turek
eed031fab0 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Add support for PHP 8.1 enums in embedded classes (#9419)
  Added class-string typehint on $targetEntity (#9415)
  Allow DiscriminatorColumn with length=0 (#9410)
  Move UnderscoreNamingStrategyTest to correct namespace (#9414)
2022-01-24 00:05:44 +01:00
HypeMC
6d5da83c68 Add support for PHP 8.1 enums in embedded classes (#9419) 2022-01-23 23:56:36 +01:00
Alexander M. Turek
328f36846e Switch tests to the middleware logging system (#9418) 2022-01-23 23:55:07 +01:00
jworman
5f01dd8d09 Added class-string typehint on $targetEntity (#9415) 2022-01-23 20:09:41 +01:00
Benjamin Cremer
b596e6a665 Allow DiscriminatorColumn with length=0 (#9410) 2022-01-21 10:27:29 +01:00
Alexander M. Turek
79d3cf5880 Move UnderscoreNamingStrategyTest to correct namespace (#9414) 2022-01-20 20:49:11 +01:00
Alexander M. Turek
f7822c775d Fix types on CacheLogger implementations (#9401) 2022-01-20 00:29:39 +01:00
Sergei Morozov
8c08792f0e Rework some tests that use hardcoded DBAL mocks (#9404) 2022-01-19 17:11:57 +01:00
Alexander M. Turek
026bba23f1 Merge branch '2.11.x' into 2.12.x
* 2.11.x:
  Fix type on loadCacheEntry (#9398)
2022-01-18 23:35:01 +01:00
Alexander M. Turek
4305cb9230 Deprecate MultiGetRegion (#9397) 2022-01-18 22:50:26 +01:00
Alexander M. Turek
d7b7c28ae5 Fix type on loadCacheEntry (#9398) 2022-01-18 22:49:52 +01:00
Alexander M. Turek
2886d0dc92 Merge 2.11.x into 2.12.x (#9394)
* Expose enumType to DBAL to make native DB Enum possible (#9382)

* Accessing private properties and methods from the same class is forbidden (#9311)

Resolves issue https://github.com/doctrine/common/issues/934

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

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

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

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

Fix review issues

* Update baselines for DBAL 3.3 (#9393)

Co-authored-by: Vadim Borodavko <vadim.borodavko@gmail.com>
Co-authored-by: olsavmic <molsavsky1@gmail.com>
2022-01-18 09:45:05 +01:00
Alexander M. Turek
d6fd510c49 Update baselines for DBAL 3.3 (#9393) 2022-01-18 09:13:14 +01:00
olsavmic
a2a7d5bb01 Accessing private properties and methods from the same class is forbidden (#9311)
Resolves issue https://github.com/doctrine/common/issues/934

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

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

Update docs/en/cookbook/accessing-private-properties-of-the-same-class-from-different-instance.rst

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

Fix review issues
2022-01-17 23:15:31 +01:00
Vadim Borodavko
223b2650c4 Expose enumType to DBAL to make native DB Enum possible (#9382) 2022-01-17 10:39:16 +01:00
Alexander M. Turek
07f1c4e8f8 Merge pull request #9387 from doctrine/2.11.x 2022-01-16 21:39:56 +01:00
Vadim Borodavko
01c1644d9c Allow using Enum from different namespace than Entity (#9384) 2022-01-16 13:08:30 +01:00
Sukhdev Mohan
3eff2d4b3f Corrected ORM version and added missing dependency (#9386)
* Corrected ORM version and added missing dependency

Noticed that the version wasn't updated, pointing to 2.11.0 instead of 2.10.2. 
Also when following this tutotial ran into missing dependency for "doctrine/annotation" so added that too.

* Tutorial: Bump DBAL, YAML and Cache

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-01-16 02:28:30 +01:00
Alexander M. Turek
9ddf8b96f8 PHPStan 1.4.0 (#9385) 2022-01-16 01:22:41 +01:00
Benjamin Eberlei
3d00fa817a [GH-9380] Bugfix: Delegate ReflectionEnumProperty::getAttributes(). (#9381)
* [GH-9380] Bugfix: Delegate ReflectionEnumProperty::getAttributes().

* [GH-9380] Add test for retrieving attributes via enum property.

* [GH-9380] Add test for retrieving attributes via enum property.

* [GH-9380] Call parent ReflectionProperty ctor for best behavior.

* Update tests/Doctrine/Tests/ORM/Functional/EnumTest.php

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2022-01-16 00:06:59 +01:00
Alexander M. Turek
0809a2b671 Support enum cases as parameters (#9373) 2022-01-13 13:11:13 +01:00
Andrii Dembitskyi
c0a1404e4c Add detach as of list cascade-all operations (#9357) 2022-01-12 22:33:11 +01:00
Alexander M. Turek
bfed8cb6ed Update branch metadata for 2.11 (#9364) 2022-01-12 14:20:33 +01:00
Alexander M. Turek
09a2648f7e Fix doc blocks on ID generators (#9368) 2022-01-12 12:10:23 +01:00
Alexander M. Turek
ee591195cf Use EntityManagerInterface in type declarations (#9325) 2022-01-12 11:00:07 +01:00
Alexander M. Turek
e974313523 Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Add errors caused by the lexer update to the baselines (#9360)
2022-01-12 10:11:19 +01:00
Alexander M. Turek
1e972b6e0e Add errors caused by the lexer update to the baselines (#9360) 2022-01-12 10:06:40 +01:00
Christian Mehldau
e369cb6e73 Generated/Virtual Columns: Insertable / Updateable (#9118)
* Generated/Virtual Columns: Insertable / Updateable

Defines whether a column is included in an SQL INSERT and/or UPDATE statement.
Throws an exception for UPDATE statements attempting to update this field/column.

Closes #5728

* Apply suggestions from code review

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* Add example for virtual column usage in attributes to docs.

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2022-01-12 08:06:11 +01:00
Grégoire Paris
ec391be4f2 Merge pull request #9356 from derrabus/remove/package-versions
Remove the `composer/package-versions-deprecated` package
2022-01-11 21:03:59 +01:00
Alexander M. Turek
697e23422f Remove the composer/package-versions-deprecated package 2022-01-11 10:42:42 +01:00
Alexander M. Turek
e487b6fe2b Relax assertion to include null as possible outcome (#9355) 2022-01-10 23:09:02 +01:00
Alexander M. Turek
656f881756 Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Fix WhereInWalker description to better describe the behaviour of this class (#9268)
2022-01-09 23:48:22 +01:00
Alexander M. Turek
cd2aa487a5 Leverage generic ObjectManagerDecorator (#9312) 2022-01-09 23:10:05 +01:00
LuigiCardamone
b7d822972e Fix WhereInWalker description to better describe the behaviour of this class (#9268)
* Fix WhereInWalker description:
- change the verb "replace" with "append" to better describe the behaviour of this class

* Rephrase comment in WhereInWalker as suggested from reviewer

Co-authored-by: Alexander M. Turek <me@derrabus.de>

* Rephrase comment in WhereInWalker as suggested from reviewer

Co-authored-by: Alexander M. Turek <me@derrabus.de>

Co-authored-by: Alexander M. Turek <me@derrabus.de>
2022-01-09 23:09:28 +01:00
Alexander M. Turek
ec63f5d32a Regenerate Psalm baseline 2022-01-09 22:35:05 +01:00
Alexander M. Turek
952ccc5fc8 Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Update Psalm baseline for Persistence 2.3 (#9349)
2022-01-09 22:33:24 +01:00
Alexander M. Turek
9a2f1f380d Update Psalm baseline for Persistence 2.3 (#9349) 2022-01-09 20:11:12 +00:00
Alexander M. Turek
580b9196e6 Support readonly properties for read operations (#9316)
* Provide failing test for readonly properties

* Skip writing readonly properties if the value did not change
2022-01-09 20:15:56 +01:00
Grégoire Paris
0d911b9381 Merge pull request #9322 from derrabus/feature/psr-region-cache
PSR-6 second level cache
2022-01-09 16:23:04 +01:00
Grégoire Paris
c6d8aecc0f Merge pull request #9326 from kimhemsoe/rsm-custom-type
Add support for custom types with requireSQLConversion and ResultSetMappingBuilder::generateSelectClause()
2022-01-09 16:17:31 +01:00
Grégoire Paris
fdd3d112b0 Merge remote-tracking branch 'origin/2.10.x' into 2.11.x 2022-01-09 15:50:52 +01:00
Grégoire Paris
2fecb3cb1a Merge pull request #9341 from derrabus/bump/phpstan-psalm
PHPStan 1.3.3, Psalm 4.18.1
2022-01-09 15:48:49 +01:00
Alexander M. Turek
f3630ea16b PHPStan 1.3.3, Psalm 4.18.1 2022-01-09 15:39:44 +01:00
Grégoire Paris
fd19444761 Merge pull request #9344 from greg0ire/remove-dbal2-psalm-job
Remove Psalm job for analyzing DBAL 2
2022-01-09 15:38:56 +01:00
Grégoire Paris
4b1afb41b3 Remove Psalm job for analyzing DBAL 2
As of now, we cannot have specific config files for each DBAL version
and avoid repetition. We already have PHPStan performing checks with
DBAL 2, which could be considered enough.
2022-01-09 13:57:00 +01:00
Alexander M. Turek
f9f453f4d7 Use the readonly annotation (#9340) 2022-01-09 12:25:04 +01:00
Kim Hemsø Rasmussen
f508a4bb71 Add support for custom types with requireSQLConversion and ResultSetMappingBuilder::generateSelectClause() 2022-01-09 10:02:30 +01:00
Alexander M. Turek
5d0fbc47d0 PSR-6 second level cache 2022-01-09 02:02:50 +01:00
Alexander M. Turek
1e977426eb Fix type errors in AbstractQuery and QueryBuilder (#9275) 2022-01-09 00:26:58 +01:00
Grégoire Paris
2640f88f8a Merge pull request #9339 from greg0ire/fix-field-mapping-typing
Fix field mapping typing
2022-01-08 23:57:48 +01:00
Grégoire Paris
fa731b10ec Mark columnName as always set
This is enforced before writing to the property that holds FieldMapping
arrays.
As shown by the static analysis baselines reduction, this existence is
relied on throughout the codebase.
2022-01-08 14:12:04 +01:00
Grégoire Paris
4117ca349f Merge pull request #9304 from beberlei/EnumSupport
Add support for PHP 8.1 enums.
2022-01-08 11:49:08 +01:00
Benjamin Eberlei
2d475c9bb3 Add support for PHP 8.1 enums. 2022-01-08 09:53:11 +01:00
Grégoire Paris
6f54011e7b Merge remote-tracking branch 'origin/2.10.x' into 2.11.x 2022-01-07 20:28:54 +01:00
Grégoire Paris
760397c429 Remove ignore rules for issues fixed upstream (#9336)
The rules still should apply when using DBAL v2
2022-01-07 20:25:00 +01:00
Benjamin Eberlei
7190ac5127 [GH-9277] deprecate php driver (#9309)
* [GH-9277] Deprecate PHPDriver

* Update UPGRADE.md, fix wrong parameter

* Copy docblock to appease confused Psalm

* Talk about alternatives more
2022-01-06 10:19:42 +01:00
Alexander M. Turek
ceaefcb18d Merge 2.10.x into 2.11.x (#9331)
* Enable some previously disabled PHPCS rules (#9324)

* Fix broken type declaration (#9330)
2022-01-05 10:03:45 +01:00
Alexander M. Turek
844ce77cae Added runtime deprecation to UnitOfWork::commit() and clear() (#9327) 2022-01-05 08:14:46 +01:00
Alexander M. Turek
cf3a185b62 Document return type of getEntityState() (#9328) 2022-01-05 07:58:21 +01:00
Alexander M. Turek
efc982a48d Fix broken type declaration (#9330) 2022-01-05 07:55:33 +01:00
Alexander M. Turek
96bc214acd Enable some previously disabled PHPCS rules (#9324) 2022-01-03 23:25:34 +01:00
Alexander M. Turek
15999758a7 Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Run static analysis with language level PHP 8.1 (#9314)
  Document PHPUnit mocks with intersection types (#9318)
2022-01-02 19:36:10 +01:00
Alexander M. Turek
44aa8c2c5b Run static analysis with language level PHP 8.1 (#9314) 2022-01-02 18:01:31 +01:00
Alexander M. Turek
8c6fc5ae52 Document LockMode enums (#9319) 2022-01-02 18:01:00 +01:00
Alexander M. Turek
c4561571aa Document PHPUnit mocks with intersection types (#9318) 2022-01-02 18:00:17 +01:00
Alexander M. Turek
40a203843d Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Run PHP CodeSniffer on PHP 8.1 (#9317)
  Psalm 4.17.0 (#9315)
2022-01-02 14:16:56 +01:00
Alexander M. Turek
8b5ee54c6a Run PHP CodeSniffer on PHP 8.1 (#9317) 2022-01-02 14:15:30 +01:00
Alexander M. Turek
03fa495fbc Psalm 4.17.0 (#9315) 2022-01-01 23:41:05 +01:00
Alexander M. Turek
5901848944 Merge 2.10.x into 2.11.x (#9313) 2022-01-01 23:40:19 +01:00
Grégoire Paris
d40f9e57ff Run static analysis on PHP 8.1 (#9310)
This will make it easier to add code that leverages features only
defined since that version of PHP.
2022-01-01 20:28:17 +01:00
Alexander M. Turek
133cc95f33 Merge branch '2.10.x' into 2.11.x
* 2.10.x:
  Bump PHPStan & Psalm (#9303)
  Removing list "Lifecycle Events" (#9243)
  Drop unneeded backslashes
  Fix Hidden fields triggering error when using getSingleScalarResult() (#8340)
  Findby joined lookup (#8285)
2021-12-31 02:59:55 +01:00
Alexander M. Turek
d30e748e64 Bump PHPStan & Psalm (#9303) 2021-12-31 02:21:15 +01:00
Alexander M. Turek
98d77043d8 Fix type errors in AnnotationDriver (#9274) 2021-12-29 16:03:10 +01:00
Grégoire Paris
40d1e7bbfc Merge pull request #9214 from doctrine/2.7
Merge 2.7 into 2.10.x
2021-12-28 23:41:38 +01:00
Thomas Landauer
e8275f6e4d Removing list "Lifecycle Events" (#9243)
As announced in https://github.com/doctrine/orm/pull/9184#issuecomment-965837780
2021-12-28 14:04:58 +01:00
Alexander M. Turek
70dcffa025 Leverage get_debug_type() (#9297) 2021-12-28 08:02:16 +01:00
Alexander M. Turek
c94a9b1d8b Merge 2.10.x into 2.11.x (#9298)
* Bump reusable workflows

* Fix union type on QueryExpressionVisitorTest::testWalkComparison() (#9294)

* Synchronize Psalm baseline (#9296)

* Fix return type (#9295)

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-12-28 01:25:01 +01:00
Alexander M. Turek
6a9393e8ed Fix return type (#9295) 2021-12-28 00:49:50 +01:00
Alexander M. Turek
ab98d0ffc6 Synchronize Psalm baseline (#9296) 2021-12-28 00:49:32 +01:00
Alexander M. Turek
2ddeb79431 Fix union type on QueryExpressionVisitorTest::testWalkComparison() (#9294) 2021-12-27 23:43:09 +01:00
David ALLIX
92ff9c9108 Allow arithmetic expressions within IN operator (#9242)
* allow arithmetic expressions within IN operator

Co-authored-by: Artem Stepin <stepin.artem@gmail.com>
2021-12-27 19:03:47 +01:00
Grégoire Paris
7c58dc89c3 Merge pull request #9289 from derrabus/bump/workflows
Bump reusable workflows
2021-12-27 18:36:35 +01:00
Alexander M. Turek
b513f7c935 Bump reusable workflows 2021-12-27 13:05:20 +01:00
Alexander M. Turek
f1483f848c Merge 2.10.x into 2.11.x (#9287)
* Better explain limitations of DQL "DELETE" (#9281)

We think the current documentation does not stress these details enough, so that they are easily overlooked.

Co-authored-by: Malte Wunsch <mw@webfactory.de>

Co-authored-by: Malte Wunsch <mw@webfactory.de>

* Put actual value instead of index inside $originalEntityData. (#9244)

This fixes a bug with redundant UPDATE queries, that are executed when some entity uses foreign index of other entity as a primary key. This happens when after inserting related entities with $em->flush() call, you do the second $em->flush() without changing any data inside entities.
Fixes GH8217.

Co-authored-by: ivan <ivan.strygin@managinglife.com>

* Allow symfony/cache 6 (#9283)

* Fix XML export for `change-tracking-policy` (#9285)

* Whitelist composer plugins used by this repository (#9286)

Co-authored-by: Matthias Pigulla <mp@webfactory.de>
Co-authored-by: Malte Wunsch <mw@webfactory.de>
Co-authored-by: Ivan Strygin <feolius@gmail.com>
Co-authored-by: ivan <ivan.strygin@managinglife.com>
Co-authored-by: Fedir Zinchuk <getthesite@gmail.com>
2021-12-26 01:06:54 +01:00
Alexander M. Turek
ea4c9b21b7 Enable UnusedUse sniff again (#9267) 2021-12-25 23:06:50 +01:00
Alexander M. Turek
72edfbc270 Whitelist composer plugins used by this repository (#9286) 2021-12-25 13:04:42 +01:00
Fedir Zinchuk
5ccf2eac40 Fix XML export for change-tracking-policy (#9285) 2021-12-24 00:22:42 +01:00
Alexander M. Turek
6696b0dfbf Allow symfony/cache 6 (#9283) 2021-12-24 00:12:11 +01:00
Ivan Strygin
aead77d597 Put actual value instead of index inside $originalEntityData. (#9244)
This fixes a bug with redundant UPDATE queries, that are executed when some entity uses foreign index of other entity as a primary key. This happens when after inserting related entities with $em->flush() call, you do the second $em->flush() without changing any data inside entities.
Fixes GH8217.

Co-authored-by: ivan <ivan.strygin@managinglife.com>
2021-12-24 00:10:42 +01:00
Alexander M. Turek
130c27c1da Fix return types of cache interfaces (#9271) 2021-12-22 01:04:07 +01:00
Matthias Pigulla
f6e1dd44f0 Better explain limitations of DQL "DELETE" (#9281)
We think the current documentation does not stress these details enough, so that they are easily overlooked.

Co-authored-by: Malte Wunsch <mw@webfactory.de>

Co-authored-by: Malte Wunsch <mw@webfactory.de>
2021-12-22 00:44:25 +01:00
Alexander M. Turek
1e9973a0c0 Merge release 2.10.4 into 2.11.x (#9280) 2021-12-21 11:01:59 +01:00
Alexander M. Turek
91761738fd Fix docblocks on nullable EM properties (#9273) 2021-12-20 22:31:57 +01:00
Andrii Dembitskyi
cccb2e2fdf Docs: use canonical order for phpdoc tags, add missed semicolon (#9190) 2021-12-20 22:23:47 +01:00
Benjamin Eberlei
18138d895e Make PrimaryReadReplicaConnection enforcement explicit (#9239)
* Move primary replica connection logic into ORM explicitly.

* Housekeeping: Use full named variables

* Housekeeping: phpcs
2021-12-20 13:50:25 +01:00
Alexander M. Turek
95d434d003 Merge 2.10.x into 2.11.x (#9276)
* Docs: consistency for FQCN, spacing, etc (#9232)

* Docs: consistent spacing, consistent array-style, consistent FQCN, avoid double escaped slashes, avoid double quotes if not necessary

* Docs: use special note block instead of markdown-based style

* Docs: Quote FQCN in table with backticks to be compatible with all render engines

* Drop all mentions API doc - it is not available anymore

* Add missed FQCN for code snippets

* Revert "Fix SchemaValidator with abstract child class in discriminator map (#9096)" (#9262)

This reverts commit bbb68d0072.

* [docs] Fix wording for attributes=>parameters. (#9265)

Co-authored-by: Andrii Dembitskyi <andrew.dembitskiy@gmail.com>
Co-authored-by: olsavmic <molsavsky1@gmail.com>
Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-12-20 04:11:33 +01:00
Alexander M. Turek
70c651ebb7 Regenerate Psalm baseline (#9272) 2021-12-19 17:06:20 +01:00
Sergei Morozov
8cb62a616a Improve compatibility with Doctrine DBAL 4 (#9266)
* Improve compatibility with AbstractPlatform::getLocateExpression() in DBAL 4

* Improve compatibility with AbstractPlatform::getTrimExpression() in DBAL 4

* Improve compatibility with Connection::quote() in DBAL 4
2021-12-19 13:19:30 +01:00
Benjamin Eberlei
fa2b52c974 [docs] Fix wording for attributes=>parameters. (#9265) 2021-12-18 11:16:35 +01:00
Benjamin Eberlei
6d306c1946 Support for nesting attributes with PHP 8.1 (#9241)
* [GH-9240] Refactor Association/AttributeOverrides to use @NamedConstructorArguments with AnnotationDriver.

* [GH-9240] Add support for PHP 8.1 nested attributes.

Supported/new attributes are #[AttributeOverrides], #[AssociationOverrides], #[JoinTable] with nested joinColumns, inverseJoinColumns.

* [GH-9240] Add support for nesting Index, UniqueCosntraint into #[Table] on PHP 8.1

* Apply review comments by gregooire.

* Add documentation for new attributes.

* Add docs for new nested #[JoinTable] support of join columns

* Add docs for new nested #[Table] support of index, uniqueConstraints

* Rename "Required/Optional atttributes" to "Required/Optional parameters"

* Remove nesting for JoinTable#joinColumns and Table#indexes/uniqueConstraints again.

* Hosuekeeping: phpcs/psalm

* housekeeping

* Remove unused function imports.
2021-12-18 11:03:12 +01:00
olsavmic
5bf814032f Revert "Fix SchemaValidator with abstract child class in discriminator map (#9096)" (#9262)
This reverts commit bbb68d0072.
2021-12-18 11:01:30 +01:00
Sergei Morozov
bea5e7166c Address more DBAL 3.2 deprecations (#9256)
* Instantiate comparator via the schema manager, if possible

* Do not use AbstractPlatform::getName()
2021-12-16 23:18:18 +01:00
Alexander M. Turek
003090b70c Deprecate Setup::registerAutoloadDirectory() (#9249) 2021-12-13 23:36:10 +01:00
Andrii Dembitskyi
02a4e4099d Docs: consistency for FQCN, spacing, etc (#9232)
* Docs: consistent spacing, consistent array-style, consistent FQCN, avoid double escaped slashes, avoid double quotes if not necessary

* Docs: use special note block instead of markdown-based style

* Docs: Quote FQCN in table with backticks to be compatible with all render engines

* Drop all mentions API doc - it is not available anymore

* Add missed FQCN for code snippets
2021-12-13 23:10:01 +01:00
Alexander M. Turek
56e0ac02af Merge 2.10.x into 2.11.x (#9248) 2021-12-13 22:21:00 +01:00
Alexander M. Turek
12a70bbefb PHPCS 3.6.2, Psalm 4.15.0 (#9247) 2021-12-13 21:28:56 +01:00
Grégoire Paris
5a4ddb2870 Merge pull request #9184 from ThomasLandauer/patch-1
[Documentation] Events Overview Table: Adding "Passed Argument" column
2021-12-12 16:21:13 +01:00
Simon Podlipsky
42195060e6 Add SchemaIgnoreClasses property for #8195. (#9202)
Co-authored-by: Simon Podlipsky <simon@podlipsky.net>

Co-authored-by: Iab Foulds <ianfoulds@x-act.co.uk>
2021-12-12 13:42:07 +01:00
Alexander M. Turek
68fa55f310 Remove fallbacks for old doctrine/annotations version (#9235) 2021-12-11 17:11:34 +01:00
Thomas Landauer
0b0c3e7e58 Update docs/en/reference/events.rst
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-12-09 12:00:30 +01:00
Kevin van Sonsbeek
92434f91c7 Added psalm param to abstract addFilterConstraint (#9229) 2021-12-08 22:31:52 +00:00
Alexander Schranz
6414ad4cbb Merge pull request #9210 from alexander-schranz/patch-2
Fix making columns  optional in indexes xml schema as they can be defined via fields now
2021-12-06 00:55:01 +01:00
Alexander M. Turek
ac5aea1c81 Merge release 2.10.3 into 2.11.x (#9224) 2021-12-03 22:40:00 +01:00
Alexander M. Turek
a75605b8c3 Merge pull request #9211 from derrabus/deprecate/convert-mapping
Add deprecation hints to `orm:convert-mapping` command
2021-12-03 15:50:09 +01:00
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
Grégoire Paris
66c95a65c5 Drop unneeded backslashes 2021-12-01 21:53:36 +01:00
Bruce
62a0d7359b Fix Hidden fields triggering error when using getSingleScalarResult() (#8340)
* Fix Hidden fields triggering error when using getSingleScalarResult()

Fixes #4257
HIDDEN fields was causing the "unicity" check to fail (NonUniqueResultException), because we was counting raw data instead of gathered row data.

* Fix Coding Standards (7.4)

* Fix Coding Standards (7.4) #2

* Fix Coding Standards (7.4) - Fix whitespaces

* Fix Coding Standards (7.4) - Fix whitespaces in tests

* Fix Coding Standards (7.4) - Fix more things

* Refactor tests into separate methods

* Fix Coding Standards (7.4) - Equals sign not aligned with surrounding assignments
2021-12-01 21:52:31 +01:00
Benjamin Eberlei
2c7d7ebb48 Findby joined lookup (#8285)
* [GH-7512] Bugfix: Load metadata on object-typed  value in EntityPersisters

* [GH-7512] Refactor double check for object/entity and flatten code.

Co-authored-by: Joe Mizzi <themizzi@me.com>
2021-12-01 21:52:29 +01:00
Thomas Landauer
8b6fe52f74 Update events.rst 2021-12-01 01:01:04 +01:00
Alexander M. Turek
eabb7f84e9 Add deprecation hints to orm:convert-mapping command 2021-11-30 23:04:44 +01:00
Alexander M. Turek
f0a20dbc9c Merge 2.10.x into 2.11.x (#9213) 2021-11-30 22:37:08 +01:00
Alexander M. Turek
15ec77fa79 Suppress Psalm's ReservedWord errors (#9212) 2021-11-30 20:20:27 +01:00
Thomas Landauer
32cd2106d0 Completing links to EventArgs classes in overview table
Questions:
1. Is https://github.com/doctrine/persistence/blob/master/lib/Doctrine/Persistence/Event/LifecycleEventArgs.php correct at all? Shouldn't this be https://github.com/doctrine/orm/blob/2.10.x/lib/Doctrine/ORM/Event/LifecycleEventArgs.php, like all the others?

2. Which one is correct for `preUpdate`? https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/events.html#entity-listeners-class says `PreUpdateEventArgs`, but https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/events.html#listening-and-subscribing-to-lifecycle-events says `LifecycleEventArgs`

For the two links to `doctrine/persistence`, I'm linking to `/master/` now, which is being forwarded to `/2.2.x/`.
2021-11-30 15:51:20 +01:00
Alexander M. Turek
6857a2e8d4 Add missing deprecations for YAML metadata mapping (#9206) 2021-11-29 16:46:05 +01:00
Alexander M. Turek
5e8b34ae30 Merge pull request #9203 from derrabus/bump/dbal-3.2
Drop support for DBAL 3.1
2021-11-29 16:45:30 +01:00
Alexander M. Turek
a9b682b7c0 Drop support for DBAL 3.1 2021-11-29 10:37:05 +01:00
Alexander M. Turek
0aadc456dc Merge 2.10.x into 2.11.x (#9205)
* Adding Attributes code block (#9161)

Just that there is some real-world example somewhere ;-) see https://github.com/doctrine/orm/issues/9020#issuecomment-955582801

* Use `equal to` instead of `equal of` in `assertSqlGeneration()` (#9195)

* 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

* Psalm 4.13.1, PHPStan 1.2.0 (#9204)

Co-authored-by: Thomas Landauer <thomas@landauer.at>
Co-authored-by: Simon Podlipsky <simon@podlipsky.net>
Co-authored-by: Julien LARY <47776596+laryjulien@users.noreply.github.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-11-28 01:08:49 +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
Thomas Landauer
77b7107d05 Using const for type 2021-11-23 01:41:01 +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
Grégoire Paris
2488b4c50c Merge pull request #9196 from greg0ire/2.11.x
Merge 2.10.x up into 2.11.x
2021-11-20 15:38:36 +01:00
Grégoire Paris
ed642c72c9 Merge remote-tracking branch 'origin/2.10.x' into 2.11.x 2021-11-20 15:28:20 +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
2dde65c4ba [Documentation] Events Overview Table: Adding "Passed Argument" column
As announced in https://github.com/doctrine/orm/pull/9160#issuecomment-954304588 I'm adding the passed "EventArgs" class to the overview table. Once this is complete, my further plan is to remove the entire paragraph https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/events.html#lifecycle-callbacks-event-argument, and probably also the second code block at https://www.doctrine-project.org/projects/doctrine-orm/en/2.10/reference/events.html#entity-listeners-class

Is there a better way to link to the source code of `LifecycleEventArgs` than https://github.com/doctrine/persistence/blob/2.2.x/lib/Doctrine/Persistence/Event/LifecycleEventArgs.php ?

Also, I changed `postLoad` to `preUpdate` in the code block, to have an example that does not receive `LifecycleEventArgs` ;-)
2021-11-11 00:22:25 +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
1e971d85c4 Merging two ~identical lists on event types (#9160)
* Merging two ~identical lists on event types

Just noticed that what I added in https://github.com/doctrine/orm/pull/9128 was (in other words) already there ;-)

* Update docs/en/reference/events.rst

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

Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2021-11-06 21:32:46 +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
Grégoire Paris
2074fc3ff9 Merge pull request #9133 from judahnator/2.10.x
Adding a setup helper for attribute metadata config
2021-10-28 22:23:25 +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
Judah Wright
8fef44333b Adding a setup helper for attribute metadata config 2021-10-27 15:05:38 -07: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
3361691d0a Merge pull request #9140 from doctrine/2.10.x-merge-up-into-2.11.x_JJHD4HD8
Merge release 2.10.2 into 2.11.x
2021-10-21 20:49:48 +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
Alexander M. Turek
b6a2257758 Merge 2.10.x into 2.11.x (#9137) 2021-10-21 19:50:56 +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
Alexander M. Turek
06d9c584a3 Merge 2.10.x into 2.11.x (#9127) 2021-10-15 18:41:04 +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
Alexander M. Turek
b0381b3705 Merge release 2.10.1 into 2.11.x (#9092) 2021-10-05 15:12:04 +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
Alexander M. Turek
3984f74eb4 Deprecate ensureProductionSettings() (#9074) 2021-10-04 10:00:34 +02:00
Alexander M. Turek
ebdced6175 Deprecate AbstractHydrator::hydrateRow() (#9072) 2021-10-03 21:46:30 +00:00
Grégoire Paris
1a702075ba Merge pull request #9071 from doctrine/2.10.x
Merge up
2021-10-03 22:49:21 +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
Grégoire Paris
07e15a0038 Merge pull request #9065 from greg0ire/2.10.x
Merge up
2021-10-03 17:14:07 +02:00
Grégoire Paris
5918cfaa20 Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-10-03 17:13:24 +02:00
Grégoire Paris
73fa465c26 Merge pull request #9064 from greg0ire/use-org-token
Use org admin token
2021-10-03 17:09:48 +02:00
Grégoire Paris
e8a221d227 Use org admin token
My previous attempts to disallow running a workflow when pushing a tag
failed, so let's ensure we can run said workflow. Maybe we will be able
to understand why it happened after it happens.
2021-10-03 17:08:50 +02:00
Grégoire Paris
b734a7d155 Merge pull request #9063 from greg0ire/explicitly-disallow-workflows-for-tags
Explicitly disallow workflows for tags
2021-10-03 17:02:04 +02:00
Grégoire Paris
bbe4022566 Explicitly disallow workflows for tags
Despite what is described in the docs, it seems that there is still an
attempt to run a workflow for tags.
2021-10-03 17:01:08 +02:00
Grégoire Paris
63f3abfbe8 Avoid triggering workflows for tags
To avoid recursive workflows, Github will prevent the release bot from
pushing tags because that would result in a new workflow being triggered.
2021-10-03 16:41:29 +02:00
Grégoire Paris
22added5fa Merge pull request #9062 from greg0ire/dont-run-workflows-for-tags
Avoid triggering workflows for tags
2021-10-03 16:39:43 +02:00
Grégoire Paris
3a3b53e11d Avoid triggering workflows for tags
To avoid recursive workflows, Github will prevent the release bot from
pushing tags because that would result in a new workflow being triggered.
2021-10-03 16:36:46 +02:00
Grégoire Paris
ddcea63d0f Try using docker image directly 2021-10-03 16:23:22 +02:00
Grégoire Paris
e800f90d7c Pin laminas/automatic-releases to 1.11.1
1.12.0 and up comes with a migration to azjezz/psl that makes it
impossible to troubleshoot issues with external commands such as git push
2021-10-03 15:09:18 +02:00
Grégoire Paris
6d16147d60 Merge pull request #9061 from greg0ire/revert-to-older-automatic-releases
Revert to older automatic releases
2021-10-03 15:06:41 +02:00
Grégoire Paris
9ed1fe59f2 Pin laminas/automatic-releases to 1.11.1
1.12.0 and up comes with a migration to azjezz/psl that makes it
impossible to troubleshoot issues with external commands such as git push
2021-10-03 14:49:00 +02:00
Alexander M. Turek
f805526336 Deprecate isIdGeneratorTable and isIdentifierUuid (#9046) 2021-10-03 12:18:53 +02:00
Alexander M. Turek
2e86134c0b Merge branch '2.9.x' into 2.10.x
* 2.9.x:
  Run PHP 8.1 CI with stable dependencies (#9058)
  Duplicate testTwoIterateHydrations (#9048)
  Add PHP 8.1 to CI (#9006)
  Fix locking non-existing entity (#9053)

Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-10-02 21:22:45 +02:00
Alexander M. Turek
5f768742a0 Run PHP 8.1 CI with stable dependencies (#9058) 2021-10-02 19:37:08 +02:00
Alexander M. Turek
7a8c086d44 Add PHP 8.1 to CI (#9057) 2021-10-02 18:01:18 +02:00
Alexander M. Turek
1d4e12bc6b Duplicate testTwoIterateHydrations (#9048) 2021-10-02 17:45:29 +02:00
Alexander M. Turek
70b0f50d13 Add PHP 8.1 to CI (#9006)
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-10-02 17:20:20 +02:00
Grégoire Paris
149c4308bb Merge pull request #9056 from derrabus/improvement/foreign-key-get-columns
Remove calls to `ForeignKeyConstraint::getColumns()`
2021-10-02 17:14:03 +02:00
Alexander M. Turek
9d4fac088c Remove calls to ForeignKeyConstraint::getColumns()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-10-02 17:05:16 +02:00
Alexander M. Turek
eb27acaa65 Update documentation regarding caching (#9043) 2021-09-30 23:30:49 +02:00
Csupity Laszlo
2362aa1a7a Fix locking non-existing entity (#9053) 2021-09-30 23:29:34 +02:00
Kévin Dunglas
f414e57d82 fix: prevent TypeError in QueryBuilder joins (#9050) 2021-09-30 06:03:33 +00:00
Alexander M. Turek
13543df649 Merge pull request #9049 from derrabus/merge/2.9.x
Merge 2.9.x into 2.10.x
2021-09-29 23:15:15 +02:00
Alexander M. Turek
1d7fdde81d Merge branch '2.9.x' into merge/2.9.x
* 2.9.x:
  Minor rewording (#8435)
  Don't presume one-to-one lookup returned an entity  (#9028)
  Minor change about double The (#9038)
  Remove duplicate comment (#9036)
  Fix docblock types for some nullable properties (#9024)
  Explicitly allow to use `Comparison` and `Composite` in JOIN conditions (#9022)
  Fix some typehints in QueryBuilder
  Bump PHPStan (#9014)
  Add tests for advanced types in collection matching
  Use types in collection persister

Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-09-29 20:33:01 +02:00
Thomas Landauer
5326736571 Minor rewording (#8435)
Emphasizing the (counter-intuitive) fact that preUpdate is called inside **flush** - cause this was causing me some confusion, see https://github.com/symfony/symfony/issues/39894
2021-09-28 09:41:16 +02:00
Greg Tyler
78d07b0bd2 Don't presume one-to-one lookup returned an entity (#9028)
If `$this->em->find()` returns null, don't treat it like an object. Instead, just set the field to null and back out of the switch statement.

Fixes #9027
2021-09-27 12:43:35 +02:00
Loenix
51ff4713b3 Minor change about double The (#9038) 2021-09-27 08:50:16 +00:00
Jérémy
c0f70204d1 Remove duplicate comment (#9036) 2021-09-23 12:47:01 +00:00
Javier Spagnoletti
2575aa5120 Fix docblock types for some nullable properties (#9024) 2021-09-22 23:48:49 +02:00
Javier Spagnoletti
1f6401ee0a Explicitly allow to use Comparison and Composite in JOIN conditions (#9022) 2021-09-20 06:09:05 +02:00
Grégoire Paris
248ff82f83 Merge pull request #9017 from norkunas/fix-typehints
Fix some typehints in QueryBuilder
2021-09-16 16:44:29 +01:00
Tomas
f1db7d7fa2 Fix some typehints in QueryBuilder 2021-09-16 15:26:18 +03:00
Alexander M. Turek
0bcc3ee4e9 Bump PHPStan (#9014) 2021-09-15 15:46:59 +02:00
Grégoire Paris
0bd651abda Merge pull request #9010 from sztyup/2.9.x
Fix ignoring custom types for PersistentCollection matching()
2021-09-15 08:02:57 +01:00
Alexander M. Turek
334ca18171 Document fluent interfaces (#9009) 2021-09-13 21:25:33 +02:00
Laszlo_Csupity
ff978ce4d8 Add tests for advanced types in collection matching 2021-09-13 13:56:13 +02:00
Laszlo_Csupity
128ebe630b Use types in collection persister 2021-09-13 13:55:41 +02:00
Alexander M. Turek
6371081593 Use PSR-6 for accessing the query cache (#9004) 2021-09-13 12:39:32 +02:00
Alexander M. Turek
31d8bd7a5e Merge pull request #9008 from greg0ire/2.10.x
Merge 2.9.x up into 2.10.x
2021-09-13 12:16:40 +02:00
Grégoire Paris
dee58cfefd Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-09-13 12:07:43 +02:00
Grégoire Paris
71f1fdb668 Merge pull request #9007 from derrabus/test/query-get-cache
Add tests for Query::getQueryCacheDriver()
2021-09-13 11:06:04 +01:00
Alexander M. Turek
85488d69e2 Add tests for Query::getQueryCacheDriver()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-09-13 10:08:58 +02:00
Alexander M. Turek
5c7e6689fc Switch cache configuration to PSR-6 (#9002) 2021-09-11 23:16:31 +02:00
Grégoire Paris
5b3fb6ac56 Merge pull request #8999 from derrabus/merge/2.9.x
Merge 2.9.x into 2.10.x
2021-09-11 16:36:44 +01:00
Alexander M. Turek
65839235ce Merge branch '2.9.x' into merge/2.9.x
* 2.9.x:
  Remove Proxy from EntityManagerInterface contract
  Add extension point for the "embedded" XML node (#8992)
  Fix return type at `EntityManagerInterface::get(Partial)Reference()` (#8922)
  Fix class casing and avoid name collisions
  Remove unused performance base test class
  Drop unused test base classes
  Fix mapped superclass missing in discriminator map
2021-09-11 16:53:52 +02:00
Grégoire Paris
d1cd8047fa Merge pull request #9001 from derrabus/sa/em-get-reference
Remove Proxy from EntityManagerInterface contract
2021-09-11 15:33:26 +01:00
Alexander M. Turek
90ed9f5387 Remove Proxy from EntityManagerInterface contract
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-09-11 15:23:14 +02:00
Javier Spagnoletti
04d28a9362 Add extension point for the "embedded" XML node (#8992) 2021-09-11 14:17:37 +02:00
Grégoire Paris
fb89129fb2 Merge pull request #9000 from derrabus/bugfix/missing-imports
Fix class casing and avoid name collisions
2021-09-11 12:55:07 +01:00
Simon Podlipsky
399b69a309 Fix return type at EntityManagerInterface::get(Partial)Reference() (#8922) 2021-09-11 13:53:20 +02:00
Grégoire Paris
01ab70d204 Merge pull request #8996 from derrabus/improvement/psr6-result-cache
Support for PSR-6 result caches
2021-09-11 12:53:09 +01:00
Alexander M. Turek
45553556d5 Fix class casing and avoid name collisions 2021-09-11 13:41:46 +02:00
Alexander M. Turek
996fa777bd Support for PSR-6 result caches
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-09-11 13:20:37 +02:00
Grégoire Paris
dc1336dbc2 Include the DBAL version in coverage filenames (#8998)
Currently, files from different jobs probably overwrite each other.
2021-09-11 13:03:55 +02:00
Alexander M. Turek
b1f89a5cb8 Merge pull request #8997 from greg0ire/drop-unused-classes 2021-09-10 22:15:58 +02:00
Grégoire Paris
48f7abf697 Remove unused performance base test class
It is unused since b960170fe1
2021-09-10 21:13:32 +02:00
Grégoire Paris
2159fbee56 Drop unused test base classes
They are no longer needed since e4c7fa961e
2021-09-10 21:13:24 +02:00
Grégoire Paris
7fcab3d52e Merge pull request #8903 from olsavmic/fix-schema-validator-for-mapped-superclass-inheritance
SchemaValidator: Fix mapped superclass missing in discriminator map
2021-09-08 17:25:23 +01:00
Grégoire Paris
2d42d7835d Merge pull request #8919 from bhushan/feat/add-get-flat-array-results-by-key-for-query
feat(ScalarColumnHydrator): added ScalarColumnHydrator to get flat array results from query for single column
2021-09-08 17:02:58 +01:00
Bhushan
ed83825223 feat(ScalarColumnHydrator): get one dimensional array values for single column 2021-09-08 17:32:35 +02:00
Alexander M. Turek
beee34055a Merge pull request #8991 from derrabus/merge/2.9.x
Merge 2.9.x into 2.10.x
2021-09-08 09:07:18 +02:00
Alexander M. Turek
7abd106c8a Merge branch '2.9.x' into merge/2.9.x
* 2.9.x:
  Restore functional cache tests (#8981)
  Fix English in `note`. (#8987)
  Remove detach deprecation entry in UPGRADE.md (#8978)
  Bump to PHPStan 0.12.98 and Psalm 4.10.0 (#8979)

Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-09-08 08:57:00 +02:00
Alexander M. Turek
be2208f208 Remove unnecessary method_exists() checks (#8984) 2021-09-07 22:45:44 +02:00
Alexander M. Turek
316ba5f75e Restore functional cache tests (#8981) 2021-09-07 22:45:12 +02:00
ash-m
a08b6306d3 Fix English in note. (#8987)
Improper agreement; either:
 - Doctrine does not EVER touch ...
 - Doctrine NEVER touches ...
2021-09-07 22:44:43 +02:00
Simon Berger
21e71af13f Remove detach deprecation entry in UPGRADE.md (#8978) 2021-09-06 19:46:48 +02:00
Alexander M. Turek
f352b2a7ed Bump to PHPStan 0.12.98 and Psalm 4.10.0 (#8979) 2021-09-06 15:14:20 +02:00
Grégoire Paris
7bf1ad1a5a Merge pull request #8964 from derrabus/feature/dbal-3
DBAL 3
2021-08-31 22:42:46 +02:00
Alexander M. Turek
9de601f377 Merge pull request #8966 from doctrine/2.9.x
Merge 2.9.x into 2.10.x
2021-08-30 00:34:08 +02:00
carnage
df5086196f Added clarification of using change tracking policy on entities with embeddables (#7495)
* Added clarification of using change tracking policy on entities with embeddables

* Apply suggestions from code review

Co-Authored-By: carnage <carnage@users.noreply.github.com>

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-08-29 23:44:14 +02:00
Grégoire Paris
a427d7d852 Merge pull request #8961 from greg0ire/drop-table
Deprecate / remove TABLE id generator strategy
2021-08-29 23:43:09 +02:00
Grégoire Paris
efbcca3cb6 Get dbname from connection params first
Getting the database name from a connection object results in a PDO
object being created, which might in turn result in an error message if
the database does not exist. For instance it does with PostgreSQL.
In some other situations, like when using sqlite, there is no database
name though, so we still have to fallback on the previous behavior.
2021-08-29 21:08:17 +02:00
Alexander M. Turek
c65cc91f5b Support for DBAL 3 2021-08-29 21:08:17 +02:00
Grégoire Paris
d5f65ba62e Merge pull request #8962 from greg0ire/dont-swallow-exceptions
Stop swallowing exceptions
2021-08-29 20:54:57 +02:00
Grégoire Paris
ef9c984bcd Merge pull request #8946 from derrabus/bugfix/dbal-3-platforms
Support for DBAL 3's platform classes
2021-08-29 16:07:49 +02:00
Grégoire Paris
3074a4b02d Merge pull request #8932 from greg0ire/drop-support-for-generating-json-array-fields
Drop support for generating json array fields
2021-08-29 15:48:17 +02:00
Alexander M. Turek
fdbc6b6c13 Support for DBAL 3's platform classes
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-29 15:27:28 +02:00
Grégoire Paris
ea584992d5 Drop support for generating JSON_ARRAY fields
JSON_ARRAY has been deprecated in favor of JSON for a while, we should
not encourage people to generate new entities with it, since it will
introduce technical debt for them.
Support for JSON is added instead.
2021-08-29 14:40:29 +02:00
Grégoire Paris
96b4c763e4 Stop swallowing exceptions
This was probably done in order to get rid of exceptions about tables
already existing, but may and does swallow other exceptions as well, for
instance exceptions about sequences failing to be created on Oracle
because the identifier is too long. This makes it unnecessarily hard to
understand what is going on.
2021-08-28 18:02:41 +02:00
Grégoire Paris
0b55275418 Deprecate / remove TABLE id generator strategy
This strategy has been marked as TODO for more than 14 years. It should
be OK to remove some things related to it since they lead to an
exception being thrown.
2021-08-28 11:02:06 +02:00
Grégoire Paris
1963733311 Merge pull request #8959 from norkunas/fix-typehint
Fix `getEntityChangeSet` return typehint
2021-08-27 08:27:04 +02:00
Grégoire Paris
a06bbafd6a Merge pull request #8957 from derrabus/remove/connection-helper
Only wire ConnectionHelper if it's available
2021-08-25 19:33:54 +02:00
Grégoire Paris
250f7acc98 Merge pull request #8960 from inarli/2.9.x
Fix typo
2021-08-25 19:32:36 +02:00
İlkay Narlı
82f8a7c56a Fix typo 2021-08-25 17:54:14 +03:00
Alexander M. Turek
b345488272 Remove calls to fixSchemaElementName() (#8941) 2021-08-25 15:06:06 +02:00
Tomas
1de4020dc9 Fix getEntityChangeSet return typehint 2021-08-25 12:38:44 +03:00
Alexander M. Turek
dc6ed8716d Only wire ConnectionHelper if it's available
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-24 16:34:00 +02:00
Grégoire Paris
a8a9b2ae75 Merge pull request #8953 from derrabus/improvement/create-schema-manager
Don't call deprecated `getSchemaManager()`
2021-08-24 08:21:25 +02:00
Grégoire Paris
e03a30bd85 Merge pull request #8954 from derrabus/bugfix/dbal-exception
Fix references to deprecated `DBALException`
2021-08-24 08:19:26 +02:00
Alexander M. Turek
16357c5666 Fix references to deprecated DBALException
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-24 04:59:12 +02:00
Alexander M. Turek
131cc17384 Don't call deprecated getSchemaManager()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-24 04:41:36 +02:00
Grégoire Paris
c18b474bbf Merge pull request #8934 from derrabus/remove/sql-result-casing
Remove calls to `AbstractPlatform::getSQLResultCasing()`
2021-08-23 20:46:40 +02:00
Grégoire Paris
e3b1ad5591 Merge pull request #8935 from derrabus/improvement/deprecated-calls
Remove calls to deprecated Connection methods
2021-08-23 18:32:14 +02:00
Alexander M. Turek
e6f1bb7dad Remove calls to AbstractPlatform::getSQLResultCasing() 2021-08-23 16:55:33 +02:00
Alexander M. Turek
730143e39b Remove calls to deprecated Connection methods 2021-08-23 16:54:59 +02:00
Alexander M. Turek
5cd00a50b2 Remove UUID generator strategy from fixtures (#8947) 2021-08-23 16:47:19 +02:00
Alexander M. Turek
3b8b3f9034 Remove ImportCommand from console (#8948) 2021-08-23 16:41:25 +02:00
Alexander M. Turek
bbe0b17b93 Don't pass false as lock mode to appendLockHint() (#8937) 2021-08-23 16:25:49 +02:00
Alexander M. Turek
7446569cf4 Remove remaining call to prefersSequences() (#8942) 2021-08-23 16:24:35 +02:00
Alexander M. Turek
930c2e093c Remove calls to EchoSQLLogger (#8940) 2021-08-23 16:23:34 +02:00
Alexander M. Turek
2154b513af Make mock layer compatible with DBAL 3 (#8949) 2021-08-23 16:22:43 +02:00
Grégoire Paris
93508438fa Merge pull request #8945 from greg0ire/document-possible-null-variable 2021-08-23 14:22:41 +02:00
Grégoire Paris
1490b2c3bb Merge pull request #8952 from greg0ire/ditch-simple-annotation-reader-2 2021-08-23 14:20:40 +02:00
Grégoire Paris
760abfc316 Drop more usages of SimpleAnnotationReader 2021-08-23 14:05:52 +02:00
Grégoire Paris
a1c15778ae Merge pull request #8951 from doctrine/2.9.x-merge-up-into-2.10.x_Ryg07QLG 2021-08-23 13:05:04 +02:00
Grégoire Paris
4f9c104ec9 Merge tag '2.9.5' into 2.9.x-merge-up-into-2.10.x_Ryg07QLG
2.9.x bugfix release (patch)

- Total issues resolved: **0**
- Total pull requests resolved: **2**
- Total contributors: **2**

 - [8930: Introduce 2.10 to readme](https://github.com/doctrine/orm/pull/8930) thanks to @SenseException

 - [8895: Implement &#95;&#95;serialize() and &#95;&#95;unserialize()](https://github.com/doctrine/orm/pull/8895) thanks to @derrabus
2021-08-23 12:35:37 +02:00
Grégoire Paris
77cc86ed88 Merge pull request #8916 from greg0ire/failing-test-8914
Check current class' discriminator map
2021-08-23 12:20:22 +02:00
Grégoire Paris
627113dc60 Merge pull request #8950 from derrabus/bump/phpstan
PHPStan 0.12.96
2021-08-23 00:02:24 +02:00
Alexander M. Turek
234829644c PHPStan 0.12.96
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-22 23:45:59 +02:00
Grégoire Paris
af4ecbadab Document possibly-null member variables
Many of the variables in AbstractHydrator are not initialized in the
constructor, and should be documented as possibly null because of that.
Introducing accessors that perform null checks allows to to have to do
these null checks when using the accessors.
Making the member variables private would be a backwards-compatibility
break and could be considered for the next major version.

This makes Psalm's and PHPStan's baselines smaller, and should make
implementing new hydrators easier.
2021-08-22 22:12:00 +02:00
Grégoire Paris
b20743b352 Merge pull request #8943 from simPod/wrap-types
Add missing EntityManagerInterface argument to callable that is being passed to `EM::wrapInTransaction()`
2021-08-22 18:17:41 +02:00
Grégoire Paris
e546cdef51 Merge pull request #8944 from derrabus/bugfix/datetime-constant
Remove references to `Type::DATETIME`
2021-08-22 18:10:22 +02:00
Alexander M. Turek
5f3e17152b Remove references to Type::DATETIME
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-22 17:43:07 +02:00
Simon Podlipsky
0d6ff230da Add missing EntityManagerInterface argument to callable that is being passed to EM::wrapInTransaction() 2021-08-22 17:26:57 +02:00
Grégoire Paris
14da92cf6b Merge pull request #8939 from derrabus/remove/driver-get-name
Remove calls to `Driver::getName()`
2021-08-22 16:27:48 +02:00
Grégoire Paris
563f3bdd85 Merge pull request #8938 from derrabus/bump-psalm
Bump Psalm to 4.9.3
2021-08-22 16:26:56 +02:00
Marcin Czarnecki
8bed63090b Throw exception NotSupported Exception for UuidGenerator with doctrine/dbal:3.x. (#8898)
Generating `getGuidExpression` has been removed in doctrine/dbal:3.x.

Partially fixes #8884
2021-08-22 16:05:22 +02:00
Alexander M. Turek
4f28ad6ccc Remove calls to Driver::getName()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-22 15:56:18 +02:00
Alexander M. Turek
3f98633704 Bump Psalm to 4.9.3
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-22 15:43:55 +02:00
Grégoire Paris
e7758866c9 Merge pull request #8936 from derrabus/bugfix/reset-baseline
Reset Psalm baseline
2021-08-22 14:51:30 +02:00
Alexander M. Turek
1b1d1a246f Reset Psalm baseline
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-22 14:18:08 +02:00
Grégoire Paris
db175020e0 Merge pull request #8928 from simPod/wrap-types
Add types to `EM::wrapInTransaction()`
2021-08-21 16:06:49 +02:00
Grégoire Paris
1de28c2cab Merge pull request #8930 from doctrine/2.10-readme
Introduce 2.10 to readme
2021-08-21 16:05:17 +02:00
Claudio Zizza
565987f583 Introduce 2.10 to readme 2021-08-20 21:14:25 +02:00
Simon Podlipsky
44bea09b10 Add types to EM::wrapInTransaction() 2021-08-19 16:35:22 +02:00
Grégoire Paris
ae10af0259 Check current class' discriminator map
A class can be in its own discriminator map, as described in the
documentation example at
https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/inheritance-mapping.html#single-table-inheritance
Checking only the current class' discriminator map should be enough,
since it is set to a copy of its parent's discriminator map earlier.

Fixes #8914
2021-08-15 11:59:11 +02:00
Grégoire Paris
d636d79686 Merge pull request #8895 from derrabus/bugfix/serializable
Implement __serialize() and __unserialize()
2021-08-15 11:56:49 +02:00
Grégoire Paris
aee197f027 Merge pull request #8904 from carnage/refactoring-tests-backport
Refactoring more tests
2021-08-14 21:22:49 +02:00
Carnage
38c0f2b205 Change assertion order to ensure query count is tested correctly 2021-08-14 14:14:11 +01:00
Carnage
3dfbce1f40 Tidy up CS errors 2021-08-14 13:57:39 +01:00
Carnage
ad2cbd6afe Fix PHP Unit deprecations and removed methods 2021-08-14 13:31:55 +01:00
Gabriel Caruso
f34215d56a Refactoring more tests 2021-08-14 11:46:47 +01:00
Grégoire Paris
163aef158b Merge pull request #8915 from basseta/address-type-deprecation
Address Type deprecation messages
2021-08-12 23:13:56 +02:00
Antoine BASSET
40f613199a Address Type deprecation messages
This makes us more compatible with DBAL v3.
We didn't address Type::JSON_ARRAY because it has been removed
2021-08-12 17:11:41 +02:00
Grégoire Paris
ed230264fb Merge pull request #8913 from doctrine/2.9.x-merge-up-into-2.10.x_GK8LNgB8
Merge release 2.9.4 into 2.10.x
2021-08-11 23:32:36 +02:00
Vincent Langlet
b19a13f4ed Override getAssociationTargetClass phpdoc (#8907)
The upstream interface now allows null to be returned, but this
implementation never returns null, and consumers are expecting it not
to.
2021-08-11 22:53:03 +02:00
Grégoire Paris
03948f891e Merge pull request #8911 from greg0ire/2.10.x
Merge 2.9.x up into 2.10.x
2021-08-11 22:23:44 +02:00
Grégoire Paris
7dfa140542 Remove uneeded assertion 2021-08-11 22:14:33 +02:00
Grégoire Paris
01e7e45744 Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-08-11 22:11:32 +02:00
Grégoire Paris
1e2c0ce72d Merge pull request #8909 from greg0ire/fix-build
Fix build
2021-08-11 22:08:05 +02:00
Grégoire Paris
6a6bcc1e2b Ignore error caused by upstream package
See https://github.com/doctrine/collections/pull/282
2021-08-11 21:48:09 +02:00
Grégoire Paris
e2f54f6fa6 Remove phpstan-specific annotation
This is a direct consequence of https://github.com/doctrine/collections/pull/274
2021-08-11 21:48:09 +02:00
Grégoire Paris
e16a768916 Adapt baseline to new error message
The signature has become more precise, and so has the error message.
2021-08-11 21:48:03 +02:00
Benjamin Eberlei
25135d429f Merge 2.9.x into 2.10.x 2021-08-11 20:21:39 +02:00
Grégoire Paris
3b9e04e971 Merge pull request #8905 from nicolas-grekas/ret-types
Add explicit `@return` type next to `#[ReturnTypeWillChange]`
2021-08-11 00:13:16 +02:00
Grégoire Paris
7c1593742c Merge pull request #8870 from derrabus/improvement/prefers-sequences
Remove calls to prefersSequences()
2021-08-10 23:24:26 +02:00
Nicolas Grekas
fca1f5240d Add explicit @return type next to #[ReturnTypeWillChange] 2021-08-10 18:51:46 +02:00
Michael Olšavský
5685dc05f6 Fix mapped superclass missing in discriminator map 2021-08-09 16:24:37 +02:00
Grégoire Paris
4fa2f6baa4 Merge pull request #8896 from derrabus/bugfix/dont-pass-null
Don't pass null as parameter
2021-08-09 08:19:12 +02:00
Grégoire Paris
245563e1cf Merge pull request #8894 from derrabus/bugfix/return-type-will-change
Fix return types for PHP 8.1
2021-08-09 08:18:46 +02:00
Grégoire Paris
f980682829 Merge pull request #8897 from scyzoryck/dbal-3-fix-connection-params
Redeclare `$_attributes` property in `Configuration` class.
2021-08-09 08:18:10 +02:00
Grégoire Paris
b600c01bca Merge pull request #8419 from simPod/more-tests
Introduce `EntityManagerInterface#wrapInTransaction()`
2021-08-08 22:45:14 +02:00
Grégoire Paris
ad43cc04ff Merge pull request #8900 from simPod/psalm-10
Regenerate psalm baseline
2021-08-08 18:01:39 +02:00
Simon Podlipsky
c45402c1eb Regenerate psalm baseline 2021-08-08 17:48:07 +02:00
Grégoire Paris
a35ce43a61 Merge pull request #8902 from greg0ire/2.10.x
Merge 2.9.x into 2.10.x
2021-08-08 17:47:08 +02:00
Grégoire Paris
ed32b4c812 Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-08-08 17:38:45 +02:00
Grégoire Paris
a5436be939 Merge pull request #8899 from simPod/psalm
Regenerate psalm baseline
2021-08-08 17:13:19 +02:00
Simon Podlipsky
1246b3b5c3 Regenerate psalm baseline 2021-08-08 16:24:49 +02:00
Simon Podlipsky
4ad5d3edbd Introduce Doctrine\ORM\EntityManagerInterface#wrapInTransaction() 2021-08-08 16:22:53 +02:00
scyzoryck
355a4a126b Redeclare $_attributes property in Configuration class that has been removed in doctrine/dbal:3.x
To keep backward compatibility we need to redeclare this property to keep using it.
Partially fixes #8884
2021-08-08 12:22:16 +02:00
Alexander M. Turek
3464591763 Don't pass null as parameter
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-08 01:39:43 +02:00
Alexander M. Turek
ae4bcd61ee Implement __serialize() and __unserialize()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-08 01:24:06 +02:00
Alexander M. Turek
dc960d7d96 Fix return types for PHP 8.1
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-08 01:10:58 +02:00
Grégoire Paris
7736429e9b Merge pull request #8892 from derrabus/bump/phpstan
Bump PHPStan to 0.12.94
2021-08-08 00:08:21 +02:00
Alexander M. Turek
edaa05a217 Remove calls to prefersSequences()
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-07 23:47:55 +02:00
Alexander M. Turek
7c6bea1307 Bump PHPStan to 0.12.94
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-08-07 22:12:21 +02:00
Grégoire Paris
c4456a2863 Merge pull request #8889 from scyzoryck/dbal-3-fix-possibly-null-argument
doctrine/dbal v3 - Make sure that values passed to are not null
2021-08-05 23:58:20 +02:00
scyzoryck
2bf0f64295 Make sure that passed values (offset and lock mode) will not be a null to meet changes in doctrine/dbal v3.
Fix psalm issues with type: `PossiblyNullArgument`, found after updating doctrine/dbal to v3. Override `null` passed as offset with `0` in calls to `Doctrine\DBAL\Platforms\AbstractPlatform::modifyLimitQuery`. Override `null` passed as lockMode with `LockMode::NONE` in calls to `Doctrine\DBAL\Platforms\AbstractPlatform::appendLockHint`.
Partialy fixes #8884
2021-08-05 22:30:58 +02:00
Grégoire Paris
12705b5c3e Merge pull request #8820 from beberlei/GH-8818-EntityNamespaceAliasDeprecation
[GH-8818] Deprecate entity namespace short aliases.
2021-08-05 19:49:39 +02:00
Benjamin Eberlei
913700b116 Remove alias in docs 2021-08-05 00:48:28 +02:00
Grégoire Paris
106ed8009a Merge pull request #8883 from dopeh/patch-1
Fix getting-started example by including cache
2021-08-05 00:20:07 +02:00
Pep
b2e00f6086 Fix getting-started example by including cache
The getting started example does not work without a valid cache library, this adds symfony/cache.
2021-08-04 23:04:46 +02:00
Benjamin Eberlei
0540485b14 Update UPGRADE.md 2021-08-04 22:29:12 +02:00
Benjamin Eberlei
e5228ba66f [GH-8818] Deprecate entity namespace short aliases. 2021-08-04 22:17:09 +02:00
Grégoire Paris
e09f126abf Merge pull request #8852 from greg0ire/backport-6943
Remove possibility to extend the doctrine mapping xml schema with anything
2021-08-04 07:43:13 +02:00
Grégoire Paris
055b646d9a Merge pull request #8769 from greg0ire/remove-unhelpful-template
Make templating Psalm-specific
2021-08-04 07:42:29 +02:00
Grégoire Paris
acdbbdacab Merge pull request #8874 from greg0ire/build-with-dbal-3
Build with DBAL 3
2021-08-03 23:52:55 +02:00
Grégoire Paris
6a267f588c Build with DBAL 3
Making these jobs green will not result in a comprehensive result of the
features, but it is a good start, and having them should give a good
overview of what is left to do.
2021-08-03 19:47:30 +02:00
Grégoire Paris
c1c3c89836 Merge pull request #8855 from piowin/GH8443-failing-test
Failing test for GH8443
2021-08-03 07:53:38 +02:00
Grégoire Paris
692277e72c Merge pull request #8862 from carnage/this-to-self
Change $this->assert* to self::assert* in unit tests
2021-08-03 07:53:00 +02:00
Grégoire Paris
47267b0da5 Merge pull request #8875 from doctrine/2.9.x
Merge 2.9.x up into 2.10.x
2021-08-02 23:57:34 +02:00
Grégoire Paris
6fc0176f87 Merge pull request #8872 from simPod/fix-build
Fix CI SA failures
2021-08-02 23:48:02 +02:00
Grégoire Paris
8bb1454d5d Merge pull request #8859 from greg0ire/backport-7110
Drop tools/sandbox
2021-08-02 19:13:22 +02:00
Simon Podlipsky
42126dc1bd Fix CI SA failures 2021-08-02 18:30:31 +02:00
Grégoire Paris
5861b0575d Merge pull request #8861 from carnage/dbal-compat
Fix compatibility with DBAL develop
2021-07-25 20:12:15 +02:00
Carnage
afe0d1c810 Change ->assert* to self::assert* 2021-07-24 19:10:38 +01:00
Grégoire Paris
bc9e0b3d2c Merge pull request #8860 from t-richard/patch-1
Fix typo in "Working with Objects"
2021-07-24 14:55:58 +02:00
Michael Moravec
0b6ab2d1a7 Fix compatibility with DBAL develop
* ResultStatement signature BC break
* PDO::FETCH_* -> FetchMode::*
* PDO::PARAM_* -> ParameterType::*
* AbstractPlatform::DATE_INTERVAL_UNIT_* -> DateIntervalUnit::*
* AbstractPlatform::TRIM_* -> TrimMode::*
2021-07-24 13:24:39 +01:00
Thibault RICHARD
aa9d0148d5 Fix typo in "Working with Objects" 2021-07-24 14:13:29 +02:00
Michael Moravec
183f4a5211 Drop tools/sandbox 2021-07-24 10:31:50 +02:00
21skills
86703cbc73 Extra brackets if no cti joins fix
Continuation of a problem from
https://github.com/doctrine/orm/pull/6812
The same problem appears if you add WITH condition to the joined entity with discriminator
2021-07-23 21:27:05 +02:00
piowin
0504c535f1 Failing test for GH8443 2021-07-23 21:27:05 +02:00
mike
84afd6c937 Removing all the occurence of any
If someone wants to override the doctrine mapping that person should
write their own mapping file.
2021-07-21 19:48:11 +02:00
mike
7065070838 replacing all the sequence by choice
The order is never important in the declaration
2021-07-21 19:45:36 +02:00
Grégoire Paris
3e18990e90 Merge pull request #8851 from greg0ire/backport-7008
Remove unused exceptions
2021-07-21 07:45:28 +02:00
Grégoire Paris
6b481be074 Remove unused exceptions 2021-07-20 23:28:50 +02:00
Grégoire Paris
52f5528d3a Merge pull request #8838 from carnage/remove-expensive-array-ops
Remove expensive array ops
2021-07-20 23:23:13 +02:00
Grégoire Paris
0db4a3936f Merge pull request #8841 from greg0ire/strict_types
Enable strict mode
2021-07-20 23:19:35 +02:00
Grégoire Paris
ccc2993610 Merge pull request #8837 from greg0ire/backport-6878
Replace spl_object_hash() with spl_object_id()
2021-07-20 23:19:18 +02:00
Grégoire Paris
b7c0e97e71 Assert child property is not null
It is then passed to a class whose constructor cannot work with null.
2021-07-20 21:56:31 +02:00
Grégoire Paris
6c7e854797 Enable strict mode 2021-07-20 21:56:29 +02:00
Grégoire Paris
efb74f3ba3 Document possible return type 2021-07-20 21:56:11 +02:00
Grégoire Paris
270e7a4234 Pass strings to SimpleXMLELement::addAttribute() 2021-07-20 21:56:10 +02:00
Grégoire Paris
decbd93af4 Cast mode to string
It might be an integer, in fact it probably is, but the phpdoc says it
might be a string too.
2021-07-20 21:55:49 +02:00
Grégoire Paris
4770008cb7 Cast string value to float
round() becomes stricter with PHP 8 and no longer accepts strings.
2021-07-20 21:55:49 +02:00
Grégoire Paris
1413111099 Ensure walkLiteral returns a string
By contract, it is supposed to.
2021-07-20 21:55:45 +02:00
Grégoire Paris
60cf2c785f Merge pull request #8846 from greg0ire/backport-6974
Use $strict param in functions that have it
2021-07-19 20:14:10 +02:00
Grégoire Paris
ee7ddac7a2 Merge pull request #8848 from greg0ire/2.10.x
Merge 2.9.x into 2.10.x
2021-07-18 12:39:24 +02:00
Grégoire Paris
e7de028d2d Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-07-18 12:05:37 +02:00
Grégoire Paris
3c4009df38 Merge pull request #8847 from greg0ire/adapt-tests-to-new-wrapping
Adapt tests to new way of wrapping
2021-07-18 12:04:40 +02:00
Grégoire Paris
0a1be2cc21 Adapt tests to new way of wrapping
Namespacing is configured here, which means instead of just one layer,
we have a PSR cache wrapped in a doctrine cache with namespacing, itself
wrapped again with a PSR cache.
2021-07-18 11:00:46 +02:00
Grégoire Paris
e39a9ba199 Regenerate Psalm baseline
It looks like using --update-baseline can make number of occurences
drop, but will not result in a removal of some code elements.
2021-07-17 10:37:07 +02:00
Grégoire Paris
65a55cea7e Use $strict param in functions that have it 2021-07-15 23:18:27 +02:00
Grégoire Paris
9e6bc35944 Merge pull request #8845 from greg0ire/backport-6929
[CS] Clean elses
2021-07-15 22:51:47 +02:00
Grégoire Paris
c289b79fb2 Merge pull request #8844 from greg0ire/backport-6549
Ditch SimpleAnnotationReader
2021-07-15 22:32:22 +02:00
Grégoire Paris
03a728dfc8 Ditch SimpleAnnotationReader
We want to get rid of it, because it is not really usable in context
when you use annotations from more than one namespace. This implies
importing classes for all annotations in use.
2021-07-15 22:23:40 +02:00
Grégoire Paris
558ebcdc83 Merge pull request #8842 from greg0ire/backport-6963
Add documentation for ToolEvents
2021-07-15 08:06:59 +02:00
Gabriel Caruso
4b06fb2424 [CS] Clean elses 2021-07-14 22:08:46 +02:00
Claudio Zizza
474218395a Add root namespace to full classname 2021-07-14 11:06:35 +02:00
Claudio Zizza
70092b9800 Update loadClassMetadata example and add namespaces 2021-07-14 11:04:41 +02:00
Claudio Zizza
cd13addcfc Add ToolEvents of SchemaTool 2021-07-14 11:03:08 +02:00
Grégoire Paris
5b6a1d7a40 Merge pull request #8836 from greg0ire/explicit-type-casts
Make implicit type casts explicit
2021-07-13 23:53:35 +02:00
Marco Pivetta
74ffc25b50 Removing useless post-array-population association hydration via array_walk() 2021-07-11 14:40:22 +02:00
Marco Pivetta
91de49e6a6 Removing is_array check on a type that can only have two possible states - using instanceof instead 2021-07-11 14:40:21 +02:00
Marco Pivetta
102484dea8 Removing useless array_key_exists() calls, using ?? operator instead 2021-07-11 14:34:21 +02:00
Marco Pivetta
f9b9a14275 Removing useless variable 2021-07-11 14:34:17 +02:00
Marco Pivetta
8b3d5848a2 Removing useless checking for never-used parameter, inlining merge operation 2021-07-11 14:33:49 +02:00
Marco Pivetta
9c5d676111 Replacing possible O(n^2) operation from PersistentCollection diffing operations 2021-07-11 14:33:43 +02:00
Michael Moravec
84ad007de3 Replace spl_object_hash() with spl_object_id()
It is more efficient, and can be provided to 7.1 users thanks to
symfony/polyfill-php72.
2021-07-10 11:55:13 +02:00
Grégoire Paris
e88d261dca Make implicit type casts explicit 2021-07-10 10:41:25 +02:00
Benjamin Eberlei
95408cd8e4 [docs] Fix sentence about how nullable types affecting column definitions. (#8835) 2021-07-08 22:22:34 +02:00
Thomas Landauer
182bdaac6b Adding fields to Index (#8830)
* Adding `fields` to Index

I guess this was just forgotten here.
Wording is taken from https://www.doctrine-project.org/projects/doctrine-orm/en/2.9/reference/annotations-reference.html#index

* Update attributes-reference.rst
2021-07-08 22:06:57 +02:00
Grégoire Paris
3c805b22b4 Merge pull request #8825 from greg0ire/github-templates
Backport Github issue and PR templates
2021-07-06 08:34:55 +02:00
Grégoire Paris
7a56ca13f8 Merge pull request #8824 from greg0ire/remove-license-header
Drop license header
2021-07-06 08:30:55 +02:00
Grégoire Paris
6a41ab56ce Backport Github issue and PR templates 2021-07-05 23:14:47 +02:00
fridde
802dd54f07 Referenced new support for PHP8 attributes (#8823) 2021-07-05 22:06:04 +02:00
Grégoire Paris
be2d99e5f6 Drop license header 2021-07-05 21:26:41 +02:00
Grégoire Paris
0a663da5b6 Merge pull request #8822 from greg0ire/2.10.x 2021-07-05 10:36:24 +02:00
Grégoire Paris
0b3fc57458 Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-07-05 10:14:57 +02:00
Grégoire Paris
836c0d3803 Merge pull request #8814 from greg0ire/backport-7158
Proposed corrected typo in demo code.
2021-07-05 10:11:50 +02:00
Grégoire Paris
aa3ed91dd2 Merge pull request #8821 from greg0ire/fix-phpstan 2021-07-05 10:01:59 +02:00
Grégoire Paris
f542dde131 Pin PHPStan to current version
We want to control upgrades to avoid suddenly failing builds.
2021-07-05 09:22:54 +02:00
Grégoire Paris
a165d4af7c Adapt ignore rules to new PHPStan version 2021-07-05 09:13:37 +02:00
Cathy Guilbaud
ff13059ba2 Proposed corrected typo in demo code.
changed $payed to $paid.
2021-07-04 17:34:22 +02:00
Grégoire Paris
c3953435dd Merge pull request #8806 from greg0ire/resurrect-phpbench
Resurrect phpbench
2021-07-03 23:21:21 +02:00
Grégoire Paris
37f60be836 Merge pull request #8813 from greg0ire/deprecate-uuid-generator
Deprecate all things related to DB-generated UUIDs
2021-07-03 22:38:44 +02:00
Grégoire Paris
9f5b38f539 Deprecate all things related to DB-generated UUIDs
DB-generated UUIDs have been deprecated in the DBAL.
2021-07-03 21:52:26 +02:00
Grégoire Paris
665e5c49ea Merge pull request #8812 from greg0ire/update-baseline
Update baseline
2021-07-03 21:31:33 +02:00
Grégoire Paris
3a10e07dfc Update baseline
Many deprecations have been addressed, particularly DBAL ones.
2021-07-03 21:21:24 +02:00
Grégoire Paris
909de45c5c Merge pull request #8811 from greg0ire/2.10.x
Merge 2.9.x into 2.10.x
2021-07-03 21:17:46 +02:00
Grégoire Paris
5aa7f75f77 Merge remote-tracking branch 'origin/2.9.x' into 2.10.x 2021-07-03 21:02:03 +02:00
Grégoire Paris
8f2aef5fa3 Merge pull request #8810 from greg0ire/update-baseline
Update Psalm baseline
2021-07-03 21:00:26 +02:00
Grégoire Paris
05be0e8bbd Update Psalm baseline
It seems some deprecations have been addressed recently.
2021-07-03 20:46:37 +02:00
Grégoire Paris
64cf6edea6 Use consistent style for the OR operator 2021-07-03 12:07:43 +02:00
Grégoire Paris
7608a40463 Run phpbench in the CI 2021-07-03 12:05:45 +02:00
Grégoire Paris
b1f6f9bfc3 Make phpbench runnable again
There seems to have been a new major version.
2021-07-03 11:57:32 +02:00
Grégoire Paris
71af666c38 Merge pull request #8796 from derrabus/improvement/hydrators-dbal-3
Migrate hydrators and queries to DBAL's new Result interface
2021-06-30 23:39:19 +02:00
Grégoire Paris
3fe980de96 Merge pull request #8801 from derrabus/bugfix/ignore-return-type-will-change
Ignore errors about missing ReturnTypeWillChange class
2021-06-30 23:02:01 +02:00
Grégoire Paris
f5d988de4e Merge pull request #8784 from greg0ire/undeprecate-passing-null
Undeprecate targetEntity omission for some types
2021-06-30 21:42:13 +02:00
Grégoire Paris
e840aef630 Merge pull request #8798 from greg0ire/backport-7776
Remove hack to access class scope inside closures
2021-06-30 08:20:29 +02:00
Gabriel Caruso
2936bac7ec Remove hack to access class scope inside closures
This is possible since 5.4.
2021-06-29 23:56:37 +02:00
Grégoire Paris
55971d2f05 Merge pull request #8799 from greg0ire/backport-6909-6910
Combine consecutive issets and unsets
2021-06-29 23:51:35 +02:00
Grégoire Paris
1f6bfe1754 Merge pull request #8800 from jderusse/fix-exception
Fix exception not thrown by "getEntityIdentifier"
2021-06-29 23:50:41 +02:00
Alexander M. Turek
0723e664e1 Migrate hydrators and queries to DBAL's new Result interface
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-06-29 23:04:15 +02:00
Alexander M. Turek
b0c7993dd6 Ignore errors about missing ReturnTypeWillChange class
Signed-off-by: Alexander M. Turek <me@derrabus.de>
2021-06-29 22:50:16 +02:00
Jérémy Derussé
796af72650 Fix exception not thrown by "getEntityIdentifier" 2021-06-29 22:32:29 +02:00
Gabriel Caruso
02174fb68f Combine consecutives issets 2021-06-28 23:33:33 +02:00
Gabriel Caruso
92c51de734 Combine consecutive unsets 2021-06-28 23:32:02 +02:00
Claudio Zizza
233d9b0276 Update session examples in docs (#8795)
The session examples contained approaches that aren't favorable for an application
and needed an overhaul using either scalar values or an DTO instead of the whole
entity with detach() and merge().
2021-06-28 23:23:40 +02:00
Grégoire Paris
b6d7826dc7 Merge pull request #8789 from greg0ire/backport-7292
Use a more concrete, less confusing example
2021-06-28 23:09:24 +02:00
Grégoire Paris
ce8de6df7f Merge pull request #8794 from derrabus/improvement/dbal-depecations
Fix deprecated DBAL calls
2021-06-28 10:58:20 +02:00
Grégoire Paris
b3ee7141eb Use a more concrete, less confusing example
I picked a toothbrush because you usually do not share it with other
persons, feel free to propose something else.
2021-06-28 00:03:29 +02:00
Grégoire Paris
73aa6e8352 Merge pull request #8791 from greg0ire/backport-docs-batch-2
Backport docs batch 2
2021-06-28 00:00:10 +02:00
Grégoire Paris
d1e5c59af9 Merge pull request #8792 from greg0ire/backport-malukenho
Backport malukenho's work
2021-06-27 23:59:19 +02:00
Grégoire Paris
e792777187 Merge pull request #8793 from greg0ire/backport-slamdunk
Backport slamdunk's work
2021-06-27 23:58:46 +02:00
Alexander M. Turek
afa837a361 Fix deprecated DBAL calls 2021-06-27 18:26:37 +02:00
Filippo Tessarotto
5a9bd0904b Apply ternary_operator_spaces 2021-06-27 12:18:14 +02:00
Filippo Tessarotto
b50d06ae58 Apply align_multiline_comment 2021-06-27 12:15:37 +02:00
Filippo Tessarotto
220201cf14 Apply escape_implicit_backslashes,heredoc_to_nowdoc 2021-06-27 12:06:02 +02:00
Filippo Tessarotto
5fa3a92ecb Apply bare heredoc_to_nowdoc 2021-06-27 12:05:50 +02:00
Jefersson Nathan
fef46263b5 Remove unused return statement
Signed-off-by: Jefersson Nathan <admin@phpse.net>
2021-06-27 11:09:23 +02:00
Jefersson Nathan
e6d9f99ac0 Remove redundant php-docs
Signed-off-by: Jefersson Nathan <admin@phpse.net>
2021-06-27 11:09:21 +02:00
Igor Pellegrini
f3e87d2c2f Fix bullet list not rendering correctly on Github
As *rst*, if reading the tutorial on the Github repository, the items
are not seen as elements of a bullet list, hence they are not rendered
and they are collapsed in a single line of text.

Fix won't affect how it renders on
[doctrine-project.org](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html).
2021-06-27 10:42:17 +02:00
Grégoire Paris
244e7c7c29 Merge pull request #8787 from greg0ire/optional-doctrine-annotations
Make doctrine/annotations an optional dependency
2021-06-27 10:15:00 +02:00
Catalin Ciobanu
53ba6b9732 Updated docblock 2021-06-26 23:04:56 +02:00
Jachim Coudenys
b3f580bf5e Fix the link to the 'Change Tracking Policies' documentation 2021-06-26 23:04:12 +02:00
Alex Rock Ancelet
774b5cbdd4 document using DTOs and entities as Value Objects 2021-06-26 22:51:22 +02:00
Gabriel Caruso
7fa3e6ec7c Use HTTPS instead of HTTP 2021-06-26 22:43:16 +02:00
Grégoire Paris
e743981f8d Merge pull request #8790 from greg0ire/backport-docs-batch
Backport docs batch
2021-06-26 22:18:30 +02:00
Haralan Dobrev
a469514ef0 Remove obsolete backslashes from underscores
These backslashes were not correctly migrated when updating the website
and it prevents search for some important terms like the query hints.
2021-06-26 18:57:58 +02:00
Jachim Coudenys
9fb13dbe28 Fix the result cache documentation (it caches raw data, not hydrated entities) 2021-06-26 17:12:28 +02:00
Adrian Föder
fc97041e49 [TASK] Streamline code block type hints for readability
This corrects a mistake with a given type hint in
the PHP code blocks as well as adds further for
consistency and brevity.
2021-06-26 16:14:05 +02:00
Claudio Zizza
f8f3b196a1 Extend documentation of arbitrary joins 2021-06-26 16:13:56 +02:00
Claudio Zizza
c01961840e Fix of variable typo in cache usage example 2021-06-26 16:13:47 +02:00
Andreas Möller
6ef1367cde Fix: Consistently format inversedBy and mappedBy attributes 2021-06-26 16:13:39 +02:00
Adrian Föder
3572b49e6a [FEATURE] Mention and link identifier generation strategies 2021-06-26 16:13:30 +02:00
Maciej Malarz
587c5f5ad6 Fix Criteria's orderBy example 2021-06-26 16:13:23 +02:00
someniatko
4f0a04e0eb Better PHPDoc for AbstractQuery cache methods
Updated useResultCache() and setResultCacheLifetime() docs to clearly state $lifetime is measured in seconds;
Added description to useResultCache()'s params. Renamed $bool => $useCache.
2021-06-26 16:13:19 +02:00
Andreas Möller
4451019dc0 Fix: Attributes vs. annotations 2021-06-26 15:56:33 +02:00
Gabriel Ostrolucký
c021426613 Fix #2935 [DDC-2236] Add note that Paginator might screw aggreg. queries 2021-06-26 15:56:09 +02:00
Gabriel Ostrolucký
243c8bff1f Fix EBNF of InExpression (StateFieldPath -> Arithmetic) 2021-06-26 15:55:18 +02:00
Gert de Pagter
5bbad8c403 Require ctype extension 2021-06-26 15:53:07 +02:00
Thomas Landauer
6c6b919788 Added UNIQUE INDEX to generated SQL schema
When I tried the example code, I got this unique index too.

Plus my `ALTER TABLE` statement was a little different from the one in the docs:
> ALTER TABLE cart ADD CONSTRAINT FK_BA388B79395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id)
Should I change that too?
2021-06-26 15:51:51 +02:00
Thomas Bisignani
b37c433080 [Documentation] Fixed comments syntax 2021-06-26 15:50:34 +02:00
Claudio Zizza
173f31a14a Add readOnly attribute to annotation example 2021-06-26 15:48:33 +02:00
Guido Sangiovanni
319acb1076 typo in class description
fixed typo in class description
2021-06-26 15:46:45 +02:00
Arman
242d2c1c41 Remove year from license 2021-06-26 15:46:14 +02:00
Jérôme Vasseur
5c95ce5c21 Fix EntityRepository constructor phpdoc
Remove redundant phpdoc from EntityRepository constructor
2021-06-26 15:45:02 +02:00
Grégoire Paris
fa583f6533 Make doctrine/annotations an optional dependency
First, there are other drivers than the annotations-based one, and
second, one of them is base on attributes, which are basically
annotations native to PHP.

Closes #8785
2021-06-26 09:51:42 +02:00
Grégoire Paris
7a78fd2900 Undeprecate targetEntity omission for some types
Some relationship types are attached to properties that can be typed
since php 7.4.
To avoid repeating the property type in targetEntity, an autodetection
feature has been developed that allows building the mapping from that
type information and annotations.
Omitting the targetEntity stays deprecated for ManyToMany as there is no
auto-detection for that yet (although one could be built by analyzing
phpdoc annotations).
2021-06-24 23:41:05 +02:00
Grégoire Paris
67fc57b5e1 Merge pull request #8780 from derrabus/improvement/deprecated-constants
Fix usages of deprecated DBAL constants
2021-06-23 09:13:32 +02:00
Grégoire Paris
b4547888d9 Merge pull request #8782 from doctrine/2.9.x
Merge 2.9.x up into 2.10.x
2021-06-23 08:28:06 +02:00
Grégoire Paris
f233e4cf6b Merge pull request #8781 from derrabus/bugfix/static-analysis
Fix Psalm/PHPStan errors
2021-06-23 08:20:28 +02:00
Alexander M. Turek
7277afefb9 Fix usages of deprecated DBAL constants 2021-06-23 01:30:14 +02:00
Alexander M. Turek
b9f7e09401 Fix Psalm/PHPStan errors 2021-06-23 01:12:54 +02:00
Julio Montoya
5e91eea726 Link to correct section (#8778) 2021-06-22 13:12:54 +02:00
Julio Montoya
10922a5329 Spell "entity" properly (#8777) 2021-06-22 13:09:57 +02:00
Grégoire Paris
fbf793af0e Merge pull request #8543 from simonberger/add_missing_param_and_return_attributes
Add missing @param and @return PHPDoc attributes
2021-06-20 21:51:38 +02:00
Simon Berger
a26ae0648f Add missing @param and @Result PHPDoc attributes 2021-06-20 21:42:50 +02:00
Grégoire Paris
8bb564d5fe Limit template annotations to Psalm
Phpstan requires that the template can be resolved in all cases, while
Psalm seems to tolerate this ambiguous situation.
See https://github.com/phpstan/phpstan/issues/5175#issuecomment-861437050
2021-06-16 08:13:57 +02:00
Grégoire Paris
08149ea0b9 Merge pull request #8692 from greg0ire/split_orm_exception
Split the ORMException class
2021-06-15 23:43:16 +02:00
Grégoire Paris
06844484dd Split the ORMException class 2021-06-15 23:34:35 +02:00
Matthias Pigulla
7827869191 Make ResolveTargetEntityListener deal with the DiscriminatorMap as well (#8402) 2021-06-15 08:08:15 +02:00
Grégoire Paris
23602784f8 Merge pull request #8765 from doctrine/2.9.x-merge-up-into-2.10.x_osteH8Wj
Merge release 2.9.3 into 2.10.x
2021-06-14 18:40:15 +02:00
Philipp Fritsche
82e77cf508 Bugfix: handle repeatable attributes (#8756)
* fix: handle repeatable attributes

* Restore interface compatibility

A reader is supposed to only ever return objects. By introducing
RepeatableAttributeCollection, we fulfill the interface and improve
clarity.

* refactor: accurate type declarations and returns

* refactor: remove unused use

* Ignore AttributeReader in phpstan and psalm to pass on CI running PHP 7.4.

* test: isTransient

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-06-13 12:29:22 +02:00
Grégoire Paris
1518b40dd2 Merge pull request #8758 from greg0ire/restore-bc-for-annotations
Restore bc for annotations
2021-06-10 19:12:13 +02:00
Grégoire Paris
10e41ec8bc Deprecate required of mandatory arguments 2021-06-09 23:04:16 +02:00
Grégoire Paris
303e346390 Restore backwards-compatibility
There used to be no constructor in this class, adding one with mandatory
arguments was technically a BC-break.

Fixes #8753
2021-06-09 23:04:16 +02:00
Grégoire Paris
fc7db8f59e Merge pull request #8747 from greg0ire/fix-attributes-syntax
Use correct named argument syntax in docs
2021-06-07 22:41:13 +02:00
Grégoire Paris
ae7f04ea53 Use correct named argument syntax in docs 2021-06-07 21:06:44 +02:00
Grégoire Paris
b8808099ea Merge pull request #8742 from derrabus/bugfix/return-type-will-change
Add ReturnTypeWillChange to ReflectionEmbeddedProperty
2021-06-05 23:52:49 +02:00
Alexander M. Turek
6432a3eeb2 Add ReturnTypeWillChange to ReflectionEmbeddedProperty 2021-06-05 22:51:55 +02:00
Grégoire Paris
3a0f60d6c6 Merge pull request #8734 from VincentLanglet/fixMetadata
Fix metadata constructor inference by phpstan
2021-06-05 21:48:17 +02:00
Grégoire Paris
ee19cf5cfd Merge pull request #8740 from VincentLanglet/fixMetada2
Make ClassMetadata covariant
2021-06-03 10:21:39 +02:00
Vincent Langlet
66daafd597 Make ClassMetadata covariant 2021-06-03 09:04:46 +02:00
Vincent Langlet
249c4fe61b Remove currentWorkingDirectory 2021-06-01 09:28:45 +02:00
Vincent Langlet
89673c60bf Fix metadata constructor inference by phpstan 2021-05-31 23:53:58 +02:00
github-actions[bot]
f8bcd2d200 Merge release 2.9.2 into 2.10.x (#8733)
* Mark 2.8.x as unmaintained, and 2.9.x as current

* Fix ClassMetadataInfo template inference

* Fix metadata cache compatibility layer

* Bump doctrine/cache patch dependency to fix build with lowest deps

* Add generics to parameters

* Add note about performance and inheritance mapping (#8704)

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

* Adapt flush($argument) in documentation as it's deprecated. (#8728)

* [GH-8723] Remove use of nullability to automatically detect nullable status (#8732)

* [GH-8723] Remove use of nullability to automatically detect nullable status.

* [GH-8723] Make Column::$nullable default to false again, fix tests.

* Add automatic type detection for Embedded. (#8724)

* Add automatic type detection for Embedded.

* Inline statement.

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
Co-authored-by: Vincent Langlet <VincentLanglet@users.noreply.github.com>
Co-authored-by: Andreas Braun <git@alcaeus.org>
Co-authored-by: Fran Moreno <franmomu@gmail.com>
Co-authored-by: Juan Iglesias <juan.manuel.iglesias93@gmail.com>
Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
Co-authored-by: Yup <warxcell@gmail.com>
Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-05-31 17:45:06 +02:00
Yup
75b4b88c5b Add automatic type detection for Embedded. (#8724)
* Add automatic type detection for Embedded.

* Inline statement.

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-05-31 11:53:14 +02:00
Benjamin Eberlei
d9e59d6862 [GH-8723] Remove use of nullability to automatically detect nullable status (#8732)
* [GH-8723] Remove use of nullability to automatically detect nullable status.

* [GH-8723] Make Column::$nullable default to false again, fix tests.
2021-05-31 10:19:16 +02:00
Yup
5fa94969de Adapt flush($argument) in documentation as it's deprecated. (#8728) 2021-05-29 22:22:19 +02:00
Juan Iglesias
f2c3ddac97 Add note about performance and inheritance mapping (#8704)
Co-authored-by: Claudio Zizza <859964+SenseException@users.noreply.github.com>
2021-05-27 08:27:55 +02:00
Grégoire Paris
46f0da9ffa Merge pull request #8710 from franmomu/recompute
Handle generic parameters in UnitOfWork
2021-05-25 13:29:21 +02:00
Fran Moreno
1e832a6782 Add generics to parameters 2021-05-25 13:01:47 +02:00
Grégoire Paris
56bdb44efd Merge pull request #8722 from alcaeus/fix-metadata-cache-clear 2021-05-25 12:55:00 +02:00
Andreas Braun
fffac44991 Bump doctrine/cache patch dependency to fix build with lowest deps 2021-05-25 11:58:11 +02:00
Andreas Braun
e42b3d6584 Fix metadata cache compatibility layer 2021-05-25 10:38:00 +02:00
Grégoire Paris
7ab2c3abbd Merge pull request #8708 from VincentLanglet/patch-2
Fix ClassMetadaInfo template inference
2021-05-25 08:49:50 +02:00
Grégoire Paris
498c816b65 Merge pull request #8717 from greg0ire/update-branch-metadata
Mark 2.8.x as unmaintained, and 2.9.x as current
2021-05-25 00:01:21 +02:00
Vincent Langlet
eec740079d Fix ClassMetadataInfo template inference 2021-05-24 21:52:40 +02:00
Grégoire Paris
c359715a97 Mark 2.8.x as unmaintained, and 2.9.x as current 2021-05-24 21:32:26 +02:00
Benjamin Eberlei
f3e55fae9f Update .doctrine-project.json to include 2.9 stable and 2.10 upcoming 2021-05-24 17:54:12 +02:00
Michael Babker
91c3bd4121 Fix links to attribute sections (#8714) 2021-05-24 17:52:30 +02:00
Peter Gribanov
e6cf12c66f remove usage Webmozart (#8713) 2021-05-24 17:50:15 +02:00
Grégoire Paris
99d67cb77d Merge pull request #8705 from greg0ire/2.9.x
Merge 2.8.x into 2.9.x
2021-05-21 09:15:28 +02:00
Grégoire Paris
43f66d5808 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-05-21 09:04:27 +02:00
Grégoire Paris
a6577b89a2 Merge pull request #8701 from jderusse/symfony6
Allow Symfony 6.0
2021-05-20 07:58:49 +02:00
Jérémy Derussé
0ca87566a9 Allow Symfony 6.0 2021-05-20 07:48:21 +02:00
Grégoire Paris
5d01f94a36 Merge pull request #8699 from greg0ire/fix-psalm
Fix some static analysis issues
2021-05-20 07:43:12 +02:00
Grégoire Paris
3d02b02636 Update static analysis baseline files
These issues were not introduced with new code, but with upgrades.
2021-05-20 00:03:39 +02:00
Grégoire Paris
6de321cb09 Address Psalm issues introduced by persistence 2021-05-20 00:03:39 +02:00
Grégoire Paris
535bc92dc8 Merge pull request #8700 from deguif/fix-undefined-offset
Fix undefined index
2021-05-18 12:20:38 +02:00
François-Xavier de Guillebon
ebb5d03f7a Fix undefined offset 2021-05-18 10:00:19 +02:00
Grégoire Paris
8e13369621 Merge pull request #8698 from deguif/cache-deprecation
Fix cache deprecation
2021-05-17 22:15:13 +02:00
François-Xavier de Guillebon
8eff4b775a Fix cache deprecation 2021-05-17 21:33:52 +02:00
Grégoire Paris
b85403d0a2 Merge pull request #8691 from alcaeus/check-deprecations
Check for use of deprecated API with Psalm
2021-05-15 18:50:30 +02:00
Andreas Braun
22ce3adfce Move to psalm level 2
This converts more issues to errors, most notably around deprecations. This can be used to later remove deprecated API.
2021-05-15 17:01:43 +02:00
tweet9ra
3a194ad699 SimpleObjectHydrator: skip unsuit custom type before converting it (#8566)
When using inheritance, it is possible to map the same column to properties of
different child classes. This can result in the same column being selecting several
times with different aliases in one SQL query, and only one aliased field needs
to be hydrated per row.
We now check that such an aliased value is mapped to the class we are hydrated
before attempting to convert it as it might result in an error when using a custom
type that does not get the expected data to initialize php value.

Co-authored-by: Sergey Naumov <s.naumov@lamoda.ru>
2021-05-15 09:37:16 +02:00
Andreas Braun
d52dab54dd Merge pull request #8672 from alcaeus/allow-cache-2.0 2021-05-14 20:21:56 +02:00
Andreas Braun
b5ac7714bc Remove ignored phpstan errors related to doctrine/cache 2.0 2021-05-13 20:38:21 +02:00
Andreas Braun
590551d5c3 Fix setup tool tests 2021-05-13 20:16:52 +02:00
Andreas Braun
c9fb9fdb40 Improve BC layer for getMetadataCacheImpl 2021-05-13 20:16:52 +02:00
Andreas Braun
965926dcc8 Update phpstan baseline to account for doctrine/cache deprecation 2021-05-13 20:16:52 +02:00
Andreas Braun
a6e30c5f4c Fix checkstyle violations 2021-05-13 20:16:52 +02:00
Andreas Braun
30ab6f4cea Add upgrade note for cache changes 2021-05-13 20:16:52 +02:00
Andreas Braun
5e5a44dce2 Suggest using symfony/cache in setup tool 2021-05-13 20:16:52 +02:00
Andreas Braun
d7bf30b291 Fix setup tool tests 2021-05-13 20:16:51 +02:00
Andreas Braun
ce8da6623f Stop using doctrine/cache 2021-05-13 20:16:51 +02:00
Andreas Braun
2ecec0c5d6 Remove reliance on doctrine/cache implementations in tests 2021-05-13 20:16:51 +02:00
Andreas Braun
6f128e4515 Allow installing doctrine/cache 2.0 2021-05-13 20:11:14 +02:00
Benjamin Eberlei
e24b0f0be7 [GH-8589] A new approach to non-nullable typed associations for BC (#8678)
* [GH-8589] A new approach to non-nullable typed associations for BC

* Address review comment about keeping the target entity type detection.
2021-05-10 19:08:16 +02:00
Benjamin Eberlei
6753b26f73 [GH-8676] Allow nested annotations to work without parents as attributes (#8677)
* [GH-8676] Allow nested annotations to work without parents as attributes.

* Housekeeping
2021-05-09 19:58:44 +02:00
Grégoire Paris
4ccc4e19fc Merge pull request #8600 from VincentLanglet/computeChangeset
Remove internal tag from computeChangeSet
2021-05-05 19:27:39 +02:00
Simon Podlipsky
4e2009433b Reflect that default EntityManager is not always named default (#8671)
Follows up #8646
2021-05-05 18:53:34 +02:00
Grégoire Paris
c25b822217 Merge pull request #8673 from Seldaek/patch-1
Add hint for ->iterate() deprecation
2021-05-05 13:31:30 +02:00
Jordi Boggiano
c3dcc5af91 Add hint for ->iterate() deprecation 2021-05-05 10:31:33 +02:00
Grégoire Paris
b2f404b25f Merge pull request #8651 from alcaeus/deprecate-doctrine-metadata-cache
Introduce PSR-6 for metadata caching
2021-05-01 14:53:46 +02:00
Alexandr Li
d141f27875 ConvertDoctrine1Schema: Fix Doctrine 1 notnull field import (#8649)
* ConvertDoctrine1Schema: Fix Doctrine 1 `notnull` field import

* cs fix

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-05-01 13:56:41 +02:00
Andreas Braun
4691839201 Extend DoctrineTestCase to fix missing methods 2021-04-29 12:54:23 +02:00
Andreas Braun
91387382b7 Allow symfony/cache 4.4 to provide PHP 7.1 support 2021-04-29 09:48:27 +02:00
Andreas Braun
f634c64b7a Use stubs over mocks in tests
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-04-29 09:42:18 +02:00
Andreas Braun
7ba9c980b5 Introduce PSR-6 for metadata caching 2021-04-29 09:42:18 +02:00
Grégoire Paris
dacdcf2c7b Merge pull request #8662 from greg0ire/2.9.x
Merge 2.8.x into 2.9.x
2021-04-29 09:27:40 +02:00
Grégoire Paris
f296fee9e4 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-29 09:20:26 +02:00
Grégoire Paris
8555fc1d34 Merge pull request #8659 from greg0ire/make-tests-independent
Make tests independent
2021-04-29 09:07:26 +02:00
Grégoire Paris
b0826fd746 Merge pull request #8201 from oojacoboo/2.8.x
Throw Exception when unable to locate identifier
2021-04-28 15:57:50 +02:00
Jacob Thomason
fe93c2e9d5 Throw Exception that includes name of entity when unable to locate identifier 2021-04-28 15:33:03 +02:00
Grégoire Paris
850d57827f Make tests independent
It seems like IdentityMapTest cannot be run on its own when the second
level cache is enabled (with ENABLE_SECOND_LEVEL_CACHE=1).
It does work when running the whole test suite because
ExtraLazyCollectionTest disables part of that cache in its setUp()
method.
In this patch, we restore the class metadata as it was before running
setUp() and put the test in IdentityMapTest inside the group that is
excluded when running with ENABLE_SECOND_LEVEL_CACHE=1 on the CI.
2021-04-28 14:12:31 +02:00
Benjamin Eberlei
e1388fa986 [GH-8327] Make EntityManagerProvider compatible with expected DoctrineBundle usage (#8646)
* [GH-8327] Make EntityManagerProvider compatible with expected DoctrineBundle usage.

* phpcs

* [Gh-8327] Delegate to EntityManagerProvider::getDefaultManager in ConnectionFromManagerProvider
2021-04-25 19:44:12 +02:00
Grégoire Paris
9a48450481 Merge pull request #7608 from mavroprovato/patch-1
Avoid unnecessary flush after processing first row
2021-04-24 14:23:09 +02:00
Kostas Kokkoros
cff8b96dd6 Avoid unnecessary flush after processing first row
The code as is needlessly flushes after just one row is updated or
removed. It makes more sense to update after ``$batchSize`` elements are
updated or removed, just as it is in the insert case.
2021-04-24 13:01:33 +02:00
Grégoire Paris
996c1c74b3 Merge pull request #8644 from greg0ire/more-accurate-return-type
Describe return types more accurately
2021-04-22 22:31:05 +02:00
Grégoire Paris
48612e6dc6 Merge pull request #8641 from Jean85/remove-deprecated-proxy-usage
Replace deprecated Proxy usages with parent interface to reduce baseline
2021-04-19 23:37:22 +02:00
Benjamin Eberlei
ddfee26f80 Support for Array parameters in SQL filters (#8375)
* #1168 Add support for array parameters on the SQLFilter

* DDC-1168 Add support for array parameters on the SQLFilter

* [GH-2624] Rework array support to use new getParameterList()

* [DDC-1952] Change at() mocking to using returnCallback()

* [DDC-1952] Make arrays of values explicit with new setParameterList

* Adjust tests to use country as list and locale as single value.

* [DDC-1952] Add tests for new exxeption conditions.

* Apply suggestions from code review

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

Co-authored-by: Manuel Nogales <nogales.manuel@gmail.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-04-19 19:46:22 +02:00
Grégoire Paris
eb860a704e Change incorrect DBAL return types 2021-04-19 19:27:00 +02:00
Grégoire Paris
51ffcb4891 Describe return types more accurately
This fixes an SA regression introduced when using stricter types in
SchemaTool.

Fixes #8642
2021-04-19 19:09:10 +02:00
Grégoire Paris
72f500318a Merge pull request #8544 from greg0ire/bc-type-declarations
Add type declarations where backwards-compatible
2021-04-19 14:02:17 +02:00
Grégoire Paris
55f030f66b Add type declarations where backwards-compatible
This includes:
- private methods
- return type declarations of final protected methods
- return type declarations of public and protected methods of final classes

Parameter type declarations are a more delicate matter and should
probably be handled separately to make it easier to catch issues during
code review.

Type declarations can be more trusted than simple phpdoc when it
comes to static analysis, having them means we can infer the phpdoc of
calling methods with confidence.

Note that it seems that some of the phpdoc I initially inferred these
declarations from were apparently wrong, in particular some mentioning
Doctrine\Dbal\Statement when was is really passed around is
Doctrine\Dbal\Driver\Statement.
2021-04-19 13:51:00 +02:00
orklah
95af30eb72 FileLockRegion::__construct 3rd param is meant to be an int (#8640) 2021-04-19 13:29:43 +02:00
Alessandro Lai
9ea0769d78 Replace deprecated Proxy usages with parent interface to reduce baseline 2021-04-19 10:43:49 +02:00
Benjamin Eberlei
22413453da Reintroduce PHP 7.1 support (#8613)
* Reintroduce PHP 7.1 support

* phpcs

* Another object typehint

* More compatibility

* phpcs

* Reduce doctrine/inflector versions again since 1.4.4 is released.

* Housekeeping: phpcbf

* Simplify PHPUnit Polyfill abstraction.

* Missing assertDoesNotMatchRegularExpression

* phpcs

* Add 7.1 on Github actions, since dependencies now supported.

* Simplify code to work with renamed phpunit assertions and document when to remove.

* phpcs

* Downgrade target phpstan version to 7.1.0

* Run --prefer-lowest with PHP 7.1 not 7.3
2021-04-18 21:24:51 +02:00
Grégoire Paris
06fadcdd8c Merge pull request #8630 from Jean85/reduce-baseline
Reduce baseline
2021-04-18 18:50:59 +02:00
Alessandro Lai
7c56aa2141 Reduce baseline with a nullable return where needed 2021-04-18 18:39:20 +02:00
Alessandro Lai
4cdcb5f760 Reduce baseline for AbstractCollectionPersister 2021-04-18 18:39:20 +02:00
Alessandro Lai
b542b36e45 Remove baseline for DefaultCacheFactory 2021-04-18 18:39:20 +02:00
Alessandro Lai
e5a7a13e1e Remove single baseline rule from DefaultCache 2021-04-18 18:39:20 +02:00
Alessandro Lai
8336dd3779 Remove baseline for AbstractQuery 2021-04-18 18:39:14 +02:00
Grégoire Paris
b04d7a62ae Merge pull request #8548 from orklah/test2
Adding details to types in PHPDoc
2021-04-18 18:09:28 +02:00
Grégoire Paris
a959a474fd Merge pull request #8636 from greg0ire/update-gitattributes
Update ignore rules to reflect current situation
2021-04-18 17:56:47 +02:00
Benjamin Eberlei
ce128e742b [GH-5202] Implement Query::HINT_READ_ONLY flag (#7936)
* Rebase QueryHintReadOnly on 2.9.x

* Housekeeping: phpcs

* [GH-5202] Dont mark known entities as read only.

* [GH-5202] Not mark objects read only when proxy before.

* phpcs
2021-04-18 16:45:25 +02:00
Benjamin Eberlei
dac87dae06 [GH-8327] Deprecate EntityManagerHelper for a provider abstraction. (#8524)
* cli config

* [GH-8327] Deprecate EntityManager HelperSet for a provider abstraction.

* Housekeeping: phpcs

* [GH-8327] Refactor tests towards use of SingleManagerProvider instead of HelperSet.

* [GH-8327] Refactor tests towards use of SingleManagerProvider instead of HelperSet.

* [GH-8327] Refactor tests towards use of SingleManagerProvider instead of HelperSet.

* Housekeeping: cs

* Update tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* [GH-8327] Change option from entity-manager to em for consistency with DoctrineBundle.

* Add final to new methods and classes

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* [GH-8327] Bugfix: phpstan detected stricter type checks needed.

* phpcs

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-04-18 14:32:42 +02:00
Jakub Caban
a2230485b2 Fix typed properties for default metadata (#7939) (#8589)
* Make Column::$type, Column::$nullable and JoinColumn::$nullable nullable by default

* Add tests for mapped typed properties (type and nullable)

* Fix Yaml driver tests and remove driver exceptions thrown too early

* Fix PHP driver tests

* Fix static PHP driver tests

* Fix XML driver tests

* Coding Standards

* Deprecate unused MappingException method

* Add manyToOne test and check nullable at the right place

* Coding Standards

* Bugfix: Temporarily change association join columns in CascadeRemoveOrderTest to circumvent new CommitOrderCalculator bug.

* phpcs

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-04-18 14:26:41 +02:00
Benjamin Eberlei
a68aa580c5 [GH-8345] Fields for unique constraints (#8629)
* Add possibility to use fields instead of column for unique constraint and indexes (#8345)

* Document changes in annotation reference

* phpcs

* Ensure exactly one of fields/columns is set for index/uniqueConstraint

* Adapt docs to fields/columns changes

* phpcs

* Implement fields in Attribute driver and fix mapping classes constructors.

* Coding Standard

* Apply suggestions from code review

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* phpcs

Co-authored-by: Jakub Caban <kuba.iluvatar@gmail.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-04-18 14:06:30 +02:00
Grégoire Paris
5ee71c54d4 Update ignore rules to reflect current situation
We no longer use Travis, we do not use git submodules as far as I know,
and we now use baseline files as well as project metadata.
2021-04-18 10:49:48 +02:00
orklah
dc37c2cd2f psalm fixes 2021-04-17 17:11:04 +02:00
Grégoire Paris
261a405970 Merge pull request #8635 from greg0ire/2.9.x
Manually merge 2.8.x into 2.9.x
2021-04-17 16:42:07 +02:00
Grégoire Paris
1ea51d88c4 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-17 16:31:14 +02:00
Grégoire Paris
da3a9fa361 Merge pull request #8634 from orklah/static-upgrade
upgrade static tools
2021-04-17 15:41:51 +02:00
orklah
4fd81d26ff upgrade static tools 2021-04-17 13:12:35 +02:00
Benjamin Eberlei
f8e06ad31e [GH-6396] Allow custom hydrators access to meta columns via Query::HINT_INCLUDE_META_COLUMNS hint. (#8382) 2021-04-16 21:27:29 +02:00
Grégoire Paris
559c1ba806 Merge pull request #8628 from greg0ire/2.9.x
Merge 2.8.x up into 2.9.x
2021-04-16 20:08:51 +02:00
Grégoire Paris
4665758c44 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-16 19:59:27 +02:00
Grégoire Paris
e2e9f8fa97 Merge pull request #8627 from greg0ire/add-baselines
Add baseline files for static analyzers
2021-04-16 19:04:04 +02:00
Grégoire Paris
f7249ec709 Declare return type
This helps SA tools figure out that it is fine to call count on the
return value of that method.
As a side-effect, using $metadata->name is not really an option since it
is not part of the ClassMetadata interface.
2021-04-16 13:14:54 +02:00
Grégoire Paris
87dbcca454 Add baseline files for static analyzers
There are many CS and SA-related changes in the ORM as we pursue better
code quality, and easier contributions. These often involve huge
changes, which can be hard to review and inevitably lead to some
regressions. I know some of those could have been avoided if we were
using stricter levels for PHPStan and Psalm.

By adding baselines, we ensure new code is at level 5 for both tools,
which should allow us to catch the most interesting issues.
2021-04-16 09:23:11 +02:00
Grégoire Paris
ceeea8ccd1 Merge pull request #8620 from greg0ire/2.9.x
Manually merge 2.8.x into 2.9.x
2021-04-13 19:23:10 +02:00
Grégoire Paris
6e16ef8c31 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-13 18:51:39 +02:00
Grégoire Paris
305e0d6664 Merge pull request #8617 from greg0ire/cs9
Upgrade to doctrine/coding-standard 9
2021-04-13 18:48:12 +02:00
Grégoire Paris
199be94e6d Upgrade to doctrine/coding-standard 9 2021-04-13 09:00:33 +02:00
Benjamin Eberlei
09a7d9f18a [GH-6578] Add validation that inherited entity class is mapped in discriminator. (#8378) 2021-04-10 18:13:31 +02:00
Grégoire Paris
f57f33b67f Merge pull request #8606 from greg0ire/2.9.x 2021-04-09 13:33:34 +02:00
Grégoire Paris
e86cddb360 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-09 13:21:30 +02:00
Grégoire Paris
fa588af3b1 Merge pull request #8604 from janatjak/2.8.x
Fix psalm param typehint for OneToManyAssociationBuilder::setOrderBy method
2021-04-09 12:57:12 +02:00
Grégoire Paris
d4741720fa Merge pull request #8605 from greg0ire/fix-phpdoc-lsp-violations 2021-04-09 11:59:28 +02:00
Grégoire Paris
343385d060 Pin squizlabs/php_codesniffer
We are referencing rules in phpcs.xml.dist, and may experience
unexpected BC-breaks because of that when they get renamed.
2021-04-09 09:27:44 +02:00
Grégoire Paris
6d04dced03 Address sniff rename
This sniff seems to have been renamed or split in the latest version of
phpcs.
2021-04-09 09:19:10 +02:00
Grégoire Paris
22fa3a8556 Document actual return types
Some executors may return integers, for instance executors that only
execute update or delete statements.
Also, in case an integer is not returned, what's actually returned is a
Doctrine\DBAL\Driver\ResultStatement, and not a Doctrine\DBAL\Driver\Statement
2021-04-09 08:52:56 +02:00
Jakub Janata
eb05756dc3 Fix psalm param typehint for OneToManyAssociationBuilder::setOrderBy method 2021-04-08 22:52:50 +02:00
Grégoire Paris
5bb7e20708 Merge pull request #8602 from NicoHaase/fix-8599
Adjusted return type annotation for getOriginalEntityData
2021-04-07 23:22:19 +02:00
Nico Haase
a9076313c7 Adjusted return type 2021-04-07 21:06:58 +02:00
Grégoire Paris
2a87821b28 Merge pull request #8552 from acoulton/maint-phpunit-upgrade 2021-04-07 15:33:06 +02:00
acoulton
da5877d60c Only polyfill older phpunit methods when required 2021-04-07 12:08:55 +01:00
Andrew Coulton
67dfe8e1af Simplify mock building calls
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-04-07 11:07:35 +01:00
Vincent Langlet
2dfe51b396 Remove internal tag 2021-04-07 11:41:34 +02:00
Grégoire Paris
5ac036de02 Merge pull request #8594 from greg0ire/make-sure-test-is-run 2021-04-06 17:47:17 +02:00
Grégoire Paris
fda0d7b440 Merge pull request #8596 from doctrine/2.8.x-merge-up-into-2.9.x_606c485ba431f2.86881997 2021-04-06 15:06:02 +02:00
Grégoire Paris
23e1fd8ad6 Drop assertion about not being an instance of proxy
We do not want to enforce it as it is an internal details that seems to
vary from environment to environment.
2021-04-06 14:55:25 +02:00
Benjamin Eberlei
f8fa0fe069 [GH-8592] Deprecated Named (Native) Queries in Metadata/EntityRepository (#8593)
* [GH-8592] Deprecated Named (Native) Queries in Metadata and EntityRepository.

* [GH-8592] Add deprecation notice for named queries in docs [ci-skip]
2021-04-05 21:59:08 +02:00
Grégoire Paris
a588555ecd Merge pull request #8586 from KartaviK/patch-3
Additional psalm param typehint for orderBy argument in findBy method
2021-04-05 20:38:36 +02:00
Grégoire Paris
501057da83 Ensure test is suffixed with Test 2021-04-05 14:42:17 +02:00
Grégoire Paris
7de84537f6 Merge pull request #8591 from DmitriiBezborodnikov/case_insensive_parenthesis
Return case insensitive check
2021-04-05 14:40:51 +02:00
Grégoire Paris
97f8325dad Make sure tests are suffixed with Test
They will not be taken into account when running vendor/bin/phpunit
otherwise.
2021-04-05 14:32:40 +02:00
Grégoire Paris
0ebd7052d7 Drop create table at shutdown
It makes tests more isolated from each other: another test relying on
some tables including some of the ones created here may fail creating
the tables it needs because they already exist.
2021-04-05 14:03:49 +02:00
Dmitrii Bezborodnikov
5d73378b92 Return case insensitive check 2021-04-05 14:03:49 +02:00
Grégoire Paris
10572ec441 Merge pull request #8590 from VincentLanglet/patch-2
Fix phpdoc of ClassMetadataInfo::getIdentifierValues
2021-04-04 23:47:09 +02:00
Vincent Langlet
76278d801d Fix phpdoc 2021-04-04 21:19:54 +02:00
Roman Varkuta
ca80830b26 Describe $orderBy parameter as a hash
A list of string is incorrect, it actually looks like this:
['someField' => 'DESC', 'someOtherField' => 'ASC'…]`
2021-04-03 12:45:24 +02:00
Grégoire Paris
1ed89c756a Merge pull request #8582 from doctrine/2.8.x-merge-up-into-2.9.x_6066399d9875f8.96494390
Merge release 2.8.3 into 2.9.x
2021-04-02 09:12:58 +02:00
Grégoire Paris
bb078b5cb7 Merge remote-tracking branch 'origin/2.8.x' into 2.8.x-merge-up-into-2.9.x_6066399d9875f8.96494390 2021-04-02 09:00:35 +02:00
Grégoire Paris
bcb4889a2c Merge pull request #8583 from greg0ire/sync-static-analysis-workflows
Synchronize static analysis jobs with upstream
2021-04-02 08:58:50 +02:00
Grégoire Paris
961da8b0cc Synchronize static analysis jobs with upstream 2021-04-01 23:32:04 +02:00
Benjamin Eberlei
657a30f8ce [GH-6394] Bugfix: IdentifierFlattener support for association non-object values. (#8384)
* [GH-6394] Bugfix: IdentifierFlattener support for association non-object values

* [GH-6394] Bugfix: BasicEntityPersister::update used wrong identifiers for version assignment.

* Exclude MissingNativeTypeHint phpcs rule as 7.4 is not lowest version.
2021-04-01 23:16:53 +02:00
Benjamin Eberlei
c3f8996af5 Bump requirement to DBAL 2.13 (#8577) 2021-04-01 21:26:25 +02:00
Grégoire Paris
0655083e50 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-04-01 09:02:08 +02:00
Grégoire Paris
0b25d4d8b0 Merge pull request #8573 from greg0ire/fix-build
Fix build issues
2021-04-01 07:49:27 +02:00
Grégoire Paris
a88242ee6c Adapt test logic to PHP and SQLite
There seems to be at least 2 camps in the software world when it comes
to the question "What's today minus one month", today being at the end
of march.

While PHP and SQLite agree that that would be the 2nd of March, other
RDBMS than SQLite and humans will tell you that it's the last day of
February.

This patch ensures that we check one logic for SQLite, and the other
logic for other platforms.
2021-03-30 21:08:29 +02:00
Grégoire Paris
fe4964008d Accommodate 2 behaviors of symfony/console in test
Decorated text used to be wrapped too early in SymfonyStyle->block()
See https://github.com/symfony/symfony/pull/40348
The fix was not contributed to version 3, which means we have to rewrite
the test so that it passes for both the correct and the buggy version.
2021-03-30 08:41:10 +02:00
Grégoire Paris
3f3de70c3e Merge pull request #8564 from cybercitizen7/featureIncludeDirectory
Adding DIR to include statement to fix issue with pathing
2021-03-26 19:46:40 +01:00
darkw1z
eb4e317144 Adding DIR to include statement to fix issue with pathing 2021-03-26 14:04:46 +01:00
Grégoire Paris
c8f2f61ea1 Merge pull request #8556 from VincentLanglet/patch-2
Fix fieldMapping phpdoc
2021-03-26 08:26:40 +01:00
Vincent Langlet
c9502d3d0b Fix fieldMapping phpdoc 2021-03-24 15:07:08 +01:00
Benjamin Eberlei
b6b3c97436 [GH-8265] Attribute Metadata Driver (#8266)
* [GH-8265] Prototype for Attribute Metadata Driver

* [GH-8265] Skip AttributeDriverTest on PHP 7.

* [GH-8265] Fill more test entities with Attribute declarations to pass tests.

* [GH-8265] More test entity attributes for passing AttributeDriverTest.

* [GH-8265] Final changes to get AttributeDriverTest passing with test entities.

* [GH-8265] automatically update cs for new code when possible.

* [GH-8265] exclude sniffs that break because of phpcs not knowing attributes.

* [GH-8265] Fix AttributeReader styles.

* [GH-8265] Fix AttributeReader styles.

* [GH-8265] Missing changes to AttributeDriver

* [GH-8265] Fix InverseJoinColumn attribute cs violations.

* [GH-8265] Fix AbstractMappingDriverTest::_loadDriver and other CS

* [GH-8265] Coding styles

* [GH-8265] Coding styles

* [GH-8265] Coding styles

* [GH-8265] Coding styles

* [GH-8265] Convert Cache, ChangeTrackingPolicy, Column to named annotations.

* [GH-8265] Convert all annotations to named constructor for attribute support.

* [GH-8265] Style after attribute changes.

* [GH-8265] more styles

* [GH-8265] Remove workaround code for attributes.

* More cs

* More cs

* More cs

* More cs

* Add Attribute Metadata driver reference.

* Housekeeping: phpcs

* More merge conflict resolutions

* phpcs

* fix broken merge

* Change NamedArgumentConstructorAnnotation interface to use NamedArgumentConstructor annotation instead.

* phpcs

* Housekeeping: cs

* Housekeeping: cs

* Update docs with review comments

* Improve attribute docs

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>

* Rename AttributesDriver to AttributeDriver

Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
2021-03-23 13:30:57 +01:00
Benjamin Eberlei
8f6d146bc4 Bump doctrine/deprecations to at least v0.5.3 (#8553) 2021-03-22 23:23:03 +01:00
Grégoire Paris
3358ccde39 Merge pull request #8547 from greg0ire/psalm-lv6-phpdoc
Make phpdoc types correct
2021-03-21 22:11:51 +01:00
acoulton
1f4e6ebeeb Add a forward-compatibility wrapper for phpunit8 assertions
While doctrine still supports php7.2 the test cases need to run
under phpunit8 as well. However some assertion methods produce
deprecation warnings in the test output with phpunit >= 9.

This commit adds a thin forward compatiblity wrapper for the
new assertion method names so that they can be used with both
supported phpunit versions.
2021-03-18 11:25:18 +00:00
acoulton
a94db4f5c0 Fix remaining warnings from the phpunit9 upgrade
Some tests were still using deprecated assertion and mocking methods,
resulting in a long list of warnings in the phpunit output.

This commit resolves all the warnings:

* Fixes a couple of test names in `@depends` tags (presumably these
  tests were renamed at some point for coding standards).

* Changes how mocks are configured when asserting the same method
  is called multiple times with a sequence of arguments / sequence
  of return values. The old `->at` expectation is deprecated because
  it can be brittle and give unreliable results. Some of this
  mocking could probably still be refactored further, but my focus
  was on solving the deprecation with the existing setup.

* Removes one use of prophecy for mocking, in favour of using
  phpunit mock objects. Prophecy now requires an extra composer
  dependency and a trait which seems overkill given it was only
  used in one place.

* Updates to the new names for assertFileExists and assertRegExp
  (and their `not` versions) - these are functionally equivalent.

* Replaces the last few references to old PHPUnit_Framework_XXX
  classes with their namespaced equivalent. These were mostly in
  comments, or in native php `assert()` statements that were sanity
  checking mocked object types. These asserts are probably redundant
  (and are clearly not running in CI since the classes they referenced
  no longer exist).
2021-03-18 10:51:43 +00:00
Grégoire Paris
47475f3a67 Merge pull request #8532 from acoulton/bug-fix-ci-db-connection
All CI runs are using the sqlite fallback connection instead of the expected driver
2021-03-17 19:49:56 +01:00
acoulton
61c4a5da0a Rename tmpdb_ to privileged_db in test config and TestUtil
To avoid confusion, the `tmpdb_` test config values are now named
`privileged_db_` and better documented in the phpunit.xml.dist.

The TestUtil class has been refactored to more closely mirror the
structure and method / variable naming of the equivalent in
doctrine/dbal. This does not introduce any significant functional
changes. The only real difference is that the test output now prints
the selected database driver the first time it is referenced,
rather than repeating this through the test run.
2021-03-17 10:31:22 +00:00
acoulton
dd34bca4eb Upgrade previously-skipped tests to phpunit 9
These tests had not been running in CI so missed the previous
phpunit upgrade.

Note that assertions in decimal/floaty values in GH7941Test have
been changed to compare numerically with a reasonable level of
precision, instead of using regex. This is because the types
returned by the different drivers are inconsistent, and phpunit
now only allows regex comparisons on strings.
2021-03-17 10:31:22 +00:00
acoulton
3e21c50f61 Fix unit test and CI database driver / credential configuration
Builds using the github actions phpunit.xml files were not properly
recognising driver-specific configuration values, so were all
falling back to use the in-memory sqlite database instead of the
expected driver. This also meant a number of tests were skipped
as they rely on functionality not available in sqlite.

This commit addresses that by:

* REMOVING the automatic fallback to the sqlite memory database -
  phpunit.xml must now always specify explicit parameters for the
  desired connection.

* Displaying the active driver in the build output for visibility
  and debugging.

* Changing the way TestUtil loads the database config in line
  with the equivalent logic in doctrine/dbal, and to support the
  way that the config is/was specified in the phpunit.xml files
  for CI.

Note that this means a couple of the expected config variable names
have changed. Developers that are using customised phpunit.xml files
locally will need to update them to provide:

* Database config variables if they want to use the sqlite/memory
  driver - see phpunit.xml.dist for details.
* `db_driver` instead of `db_type`
* `db_user` instead of `db_username`
* `db_dbname` instead of `db_name`
* And, if in use, the equivalent changes to the `tmpdb_` values

The other change is that now if you provide any value for
`db_driver` we will attempt to create that connection type and
that will throw if other details (username / password / etc as
required by the driver) are not provided. Previously providing
partial configuration would cause TestUtil to silently fall back
to the in-memory sqlite driver.
2021-03-17 10:31:22 +00:00
Grégoire Paris
bc3592bcc8 Make phpdoc type correct 2021-03-16 19:20:11 +01:00
Grégoire Paris
4fccec1322 Merge pull request #8545 from orklah/psalm-plugins-2
remove some empty() use when safe
2021-03-15 23:51:09 +01:00
orklah
0177133385 remove unwanted check with 0 2021-03-15 23:28:20 +01:00
orklah
8df5cb84fa remove some empty() use when safe 2021-03-15 23:28:19 +01:00
Grégoire Paris
3b7275e183 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-03-14 18:57:41 +01:00
Grégoire Paris
5247c56fce Merge pull request #8539 from greg0ire/cs-20210311
🎉 Final CS batch 🎉
2021-03-14 18:47:03 +01:00
Grégoire Paris
cc37c490c2 Synchronize coding standard workflow with upstream
Now that there no longer are cs issues, we can thank diff-sniffer and
kiss it goodbye!
2021-03-13 09:55:38 +01:00
Grégoire Paris
95824efd61 Manually fix cs 2021-03-13 09:46:38 +01:00
Grégoire Paris
44d4712e64 Ignore rule about annotation phpdoc
These phpdoc is parsed by doctrine/annotations, and that package does
not understand things like array<string, mixed> yet.
2021-03-13 09:46:38 +01:00
Grégoire Paris
930f44c02f Ignore rule for externally-defined property 2021-03-13 00:08:03 +01:00
Grégoire Paris
6e3c011e65 Ignore rule about superflous comment
We can fix it with a breaking change.
2021-03-13 00:08:03 +01:00
Grégoire Paris
a82de0d422 Ignore rule about unused method
It cannot work when you call the private method like a callable.
2021-03-13 00:08:03 +01:00
Grégoire Paris
9917488179 Ignore rule about empty statements
This should be implemented in a separate pull request.
2021-03-12 08:20:46 +01:00
Grégoire Paris
93f31d2c33 Merge pull request #8533 from acoulton/test-string-lock-version
Add test coverage for passing optimistic lock version as string
2021-03-11 21:41:32 +01:00
acoulton
77356b954f Add test coverage for passing optimistic lock version as string
As discussed in #8527, when using optimistic locking with integer
version columns, Doctrine has always supported passing the lock
version as a string. For example when passing in a version
received in POST / GET.

Technically speaking this does not comply with the docs and phdoc
(which show the app explicitly casting to int before passing).

Nonetheless the maintainers decided it should continue to be valid
for now and reinstated the old soft-equals logic with #8531.

This modified test just avoids accidental changes in future.
2021-03-11 13:24:53 +00:00
Grégoire Paris
92f764206e Ignore broken rule 2021-03-11 09:11:24 +01:00
Grégoire Paris
141539673e Merge pull request #8530 from doctrine/cs-20210310
CS-batch 25/26 🤩
2021-03-11 00:05:31 +01:00
Grégoire Paris
23dc804c9b Merge pull request #8531 from beberlei/GH-8527-RevertLockEquals
[GH-8527] Revert cs fixes for entity version compares in lock+merge
2021-03-10 23:30:25 +01:00
Benjamin Eberlei
9e3baa7baa [GH-8527] Revert cs fixes for entity version compares in lock+merge 2021-03-10 22:46:07 +01:00
Grégoire Paris
322ea51ecf Manually fix cs 2021-03-10 22:17:31 +01:00
Grégoire Paris
21b046452b Merge pull request #8529 from greg0ire/cs-20210308
CS batch 24/26 🤞
2021-03-10 19:53:52 +01:00
Grégoire Paris
c57b81ada4 Manually fix cs 2021-03-09 21:15:33 +01:00
Grégoire Paris
4fa7c9c6de Merge pull request #8521 from greg0ire/cs-20210228
CS batch 23/an estimated 26
2021-03-08 19:57:18 +01:00
Benjamin Eberlei
2685b65c2b [GH-6855] Trigger deprecation for unsupported lifecycle callback mapping on embedded classes.(#8381) 2021-03-04 22:08:11 +01:00
Benjamin Eberlei
3902a4eb6e [GH-8458] Properly deprecate ConvertDoctrine1Schema (#8517) 2021-03-02 09:38:09 +01:00
Jakub Caban
b3ed525d4d Use typed properties for default metadata for #7939 (#8439)
[GH-7939] Detect column and association types from typed properties.

* Use typed properties for default metadata for #7939

* Coding Standards

* Remove $name from CmsUserTypes and adapt tests

* Factor out conditions required for typed property

* Factor out typed validation and completion methods

* Move Typed tests model to separate namespace

* Don't pass by reference, return array

* Document changes to default mapping for typed properties

* Better wording in annotation reference

* Add missing targetEntity assertion on typed association

* Try to comply with CS

* USe constants instead of strings

* Use one-line comments for single line content

* phpcs

* phpcs

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-03-01 22:13:58 +01:00
Grégoire Paris
3580517aac Manually fix cs 2021-03-01 21:49:10 +01:00
Benjamin Eberlei
4cdc6b1a71 [GH-7128] Improve OneToManyRequiresMappedBy Exception message (#8380) 2021-03-01 21:42:57 +01:00
plfort
38ccbd8638 DDC-2076 - MEMBER OF - Remove useless join over target table of ManyToMany relationship (#8438)
Co-authored-by: Pierre-Louis FORT <pierre-louis.fort@theia.fr>
2021-02-28 23:37:40 +01:00
Grégoire Paris
f9e7c3c2d8 Merge pull request #8516 from greg0ire/cs-20210227
CS batch 22/an estimated 26
2021-02-28 21:27:52 +01:00
Grégoire Paris
3600c0fbca Manually fix cs 2021-02-28 18:31:38 +01:00
Grégoire Paris
f779513042 Remove unused properties
They should have been removed as part of a6b43b93ac
2021-02-28 18:31:38 +01:00
Benjamin Eberlei
b4e6530d2d [GH-8471] Deprecate Partial DQL syntax and forcing partial loads. (#8472)
* [GH-8471] Deprecate Partial DQL syntax and forcing partial loads.
2021-02-28 18:17:12 +01:00
Diego Rin Martín
07d426edf5 Changed lock function to compare timestamps instead of DateTimeInterface objects directly. (#8508)
When using optimistic lock with DateTimeInterface based version field a bug appears due to the use of the === operator for comparing the lock version and the entity version. This comparison always resolves to false because the === operator when comparing objects is only true when both sides are the exact same instance of the object.

To fix the issue I have decided to compare timestamps instead the DateTimeInterface based objects directly, calling getTimestamp() method and doing a strict comparison.

Modified OptimisticLockException to use DateTimeInterface instead of DateTime class.

Added test suite to cover case.

Fixes #8499
2021-02-27 18:40:48 +01:00
Grégoire Paris
4afd4069be Merge pull request #8515 from greg0ire/cs-20210226
CS batch 21/an estimated 26
2021-02-27 14:30:25 +01:00
Grégoire Paris
239215c2e5 Merge pull request #8502 from greg0ire/rework-contributing-md
Rework CONTRIBUTING.md
2021-02-27 13:03:20 +01:00
Grégoire Paris
e6f11652d2 Add section for 2.9.x branch 2021-02-27 12:16:49 +01:00
Grégoire Paris
2910a73927 Rework badges urls
Some .x were missing, and ugly urlencoding can be avoided.
2021-02-27 12:10:47 +01:00
Grégoire Paris
3959b2743c Remove references to Travis 2021-02-27 12:03:35 +01:00
Grégoire Paris
658e54027e Remove trailing whitespace 2021-02-27 12:01:06 +01:00
Grégoire Paris
ba882451b0 Refer to our actual coding/standard
We do much more than just PSR 1 and 2
2021-02-27 12:01:05 +01:00
Grégoire Paris
1ed9840123 Refer to global workflow policy
We are doing things differently now, and the how is already documented.
2021-02-27 12:01:05 +01:00
Grégoire Paris
71044894a1 Manually fix cs 2021-02-26 21:30:49 +01:00
Grégoire Paris
1a41d6b87c Fix configuration mix up 2021-02-26 08:25:44 +01:00
Grégoire Paris
5dfcb08999 Merge pull request #8512 from greg0ire/cs-20210225
CS batch 20/an estimated 26
2021-02-25 23:23:24 +01:00
Grégoire Paris
284bd6fd03 Manually fix cs 2021-02-25 21:22:50 +01:00
Grégoire Paris
e40ac3e1d0 Merge pull request #8510 from greg0ire/cs-20210224
CS batch 19/an estimated 26
2021-02-24 22:41:28 +01:00
Grégoire Paris
0bce2472f2 Manually fix cs 2021-02-24 18:51:02 +01:00
Grégoire Paris
89f57de884 Merge pull request #8504 from greg0ire/cs-20210223
CS batch 18/an estimated 26
2021-02-23 23:18:42 +01:00
Grégoire Paris
ae19f40958 Merge pull request #8495 from Warxcell/fix_to_iterable_with_cache
Fix bug when using Result Cache with Query::toIterable
2021-02-23 20:16:39 +01:00
Grégoire Paris
c2d69a3c48 Merge pull request #8507 from greg0ire/address-move-away-from-master
Address move away from master
2021-02-23 18:19:47 +01:00
Grégoire Paris
6ce91dd37b Address move away from master 2021-02-23 09:24:40 +01:00
Grégoire Paris
57e6ba25c9 Merge pull request #8505 from dbu/patch-1
fix typo in changelog
2021-02-23 08:56:31 +01:00
David Buchmann
9d2e67bbb4 fix typo in changelog 2021-02-23 08:17:31 +01:00
Grégoire Paris
2dce5b20ad Manually fix cs 2021-02-22 23:50:09 +01:00
Warxcell
930859f803 Fix bug when using ResultCache with Query::toIterable.
Signed-off-by: Warxcell <warxcell@gmail.com>
2021-02-22 23:35:22 +02:00
Yup
a70c73ae3a Use RegEx to match if queryPart contains OR/AND (#8453)
This allows fixes cases of queries that contain line feeds or tabs but
do not benefit from automatic wrapping of parenthesis.
2021-02-22 20:58:06 +01:00
David Buchmann
074346b8d5 Note deprecation of AbstractQuery::iterator (#8497) 2021-02-22 20:30:05 +01:00
Grégoire Paris
9ed4a8c043 Merge pull request #8498 from greg0ire/cs-20210222
CS batch 17/an estimated 26
2021-02-22 20:25:06 +01:00
Grégoire Paris
9c917811e5 Manually fix cs 2021-02-22 09:12:04 +01:00
Grégoire Paris
f883820257 Ignore rule about wrong comment style 2021-02-22 08:48:46 +01:00
Grégoire Paris
a32045dd51 Ignore rule violated by external package 2021-02-22 07:52:57 +01:00
Grégoire Paris
672b04a55d Merge pull request #8483 from olsavmic/fix-single-scalar-hydrator-memory-leak-on-exception
Fix single scalar hydrator memory leak on exception
2021-02-21 21:12:50 +01:00
Grégoire Paris
261334aca2 Merge pull request #8494 from greg0ire/cs-20210221
CS batch 16/an estimated 26
2021-02-21 20:29:47 +01:00
Warxcell
7f6ed094cd Add test to verify that using ResultCache with Query::toIterable is failing. 2021-02-21 21:12:52 +02:00
Grégoire Paris
a792655813 Manually fix cs 2021-02-21 12:20:19 +01:00
Grégoire Paris
fb71204910 Relax assertion (#8493)
EntityManager is too restrictive, any implementation can actually be
returned here.

Closes #8488
2021-02-21 07:43:56 +01:00
Grégoire Paris
b918661cf1 Merge pull request #8492 from greg0ire/cs-20210220
CS batch 15/an estimated 26
2021-02-20 20:49:25 +01:00
Michael Olšavský
7971a53164 Method hydrateAll() does not take into account possible exception
from hydrateAllData() which in turn does not call cleanup()
2021-02-20 18:58:50 +01:00
Grégoire Paris
a175f96ae8 Manually fix cs 2021-02-20 15:37:15 +01:00
Grégoire Paris
7c1cde6471 Ignore rule that triggers on external property 2021-02-20 15:32:26 +01:00
Grégoire Paris
1ffc0cacf4 Merge pull request #8491 from greg0ire/cs-20210219
CS batch 14/an estimated 26
2021-02-20 11:10:27 +01:00
Grégoire Paris
e979d0d50f Manually fix cs 2021-02-20 00:01:41 +01:00
Grégoire Paris
553ea03079 Ignore rule about case mismatch
@group does not have to do with the Group entity at all.
2021-02-19 23:33:25 +01:00
Grégoire Paris
149014879d Ignore rule about property defined externally 2021-02-19 23:11:43 +01:00
Grégoire Paris
b991c58988 Merge pull request #8490 from greg0ire/cs-20210218
CS batch 13/an estimated 26
2021-02-19 23:08:25 +01:00
Aleksandr Frolov
ee9627b82e Update QueryBuilder::setParameters docs (#8487)
Use `ArrayCollection` instead of plain array (which is supported only for bc)
2021-02-19 01:45:14 +01:00
Grégoire Paris
e3f03414f9 Manually fix cs 2021-02-18 23:17:03 +01:00
Grégoire Paris
1f406fd3df Merge pull request #8484 from greg0ire/cs-20210217
CS batch 12/an estimated 26
2021-02-18 21:54:43 +01:00
Grégoire Paris
0ae53a6703 Merge pull request #8485 from doctrine/2.8.x-merge-up-into-2.9.x_602d59a0aa86b9.63081052
Merge release 2.8.2 into 2.9.x
2021-02-17 20:50:44 +01:00
Grégoire Paris
49864a7f57 Merge remote-tracking branch 'origin/2.8.x' into 2.8.x-merge-up-into-2.9.x_602d59a0aa86b9.63081052 2021-02-17 20:39:28 +01:00
Grégoire Paris
b747bf15ff Manually fix cs 2021-02-17 16:32:39 +01:00
Grégoire Paris
5fe85bfc03 Ignore rule about underscore in method name
We inherit from a class defined in another package.
2021-02-17 15:55:21 +01:00
Grégoire Paris
0dccf05ca8 Automatically fix cs 2021-02-17 15:55:21 +01:00
Benjamin Eberlei
e2e59e94f5 [GH-8383] deprecate notify change tracking policy (#8473)
* [GH-8383] Deprecate notify change tracking policy.

* [GH-8383] Add warning to documentation about notify change tracking policy deprecation.
2021-02-13 23:14:28 +01:00
Benjamin Eberlei
6fe388a705 Introduce doctrine/deprecations (#8466)
* Introduce doctrine/deprecations, empty out VerifyDeprecations trait for now.

* Replace more usages of VerifyDeprecations (akwardkly for now)

* Update doctrine/deprecations to v0.2.0

* Remove ORM VerifyDeprecations trait and its use.

* Use doctrine/deprecatios VerifyDeprecations trait where useful

* Housekeeping: phpcs

* Fix reference link for toIterable/iterate deprecation
2021-02-12 18:14:34 +01:00
Vincent Langlet
172a8d9414 Restrict EntityManagerInterface::getRepository (#8417) 2021-02-12 17:44:22 +01:00
Grégoire Paris
d00dbf7e2d Merge pull request #8357 from snapshotpl/add-psalm-annotation
Add psalm annotation to ArrayCollection of Parameters
2021-02-08 21:25:58 +01:00
Witold Wasiczko
17012f1fea Improve psalm types 2021-02-08 21:16:56 +01:00
Witold Wasiczko
324ac3972f Add psalm annotation for parameters 2021-02-08 21:16:25 +01:00
Benjamin Eberlei
323469cdb7 Add /*.phpunit.xml to .gitignore 2021-02-07 19:38:52 +01:00
andrews05
835030297a Add support for INDEX BY an associated entity (2.9.x) (#7918)
* Add support for INDEX BY an associated entity

This allows specifying an association in the INDEX BY clause of a query
which will index by the association's join column.

Related to #7661.

* Reintroduce IndexBy#simpleStateFieldPathExpression as deprecated property.

* Housekeeping: phpcs

* Housekeeping: phpcs

Co-authored-by: Benjamin Eberlei <kontakt@beberlei.de>
2021-02-06 11:46:18 +01:00
Grégoire Paris
4cc78d9478 Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-02-05 23:40:59 +01:00
Grégoire Paris
68d24288ce Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-02-05 20:06:04 +01:00
Grégoire Paris
5abad7c0af Merge remote-tracking branch 'origin/2.8.x' into 2.9.x 2021-01-31 00:01:45 +01:00
orklah
f0ad5f72b2 bump psalm and fix some issues on level 6 (#8409) 2021-01-08 20:30:15 +01:00
Benjamin Eberlei
cbc252f3b7 Add Doctrine\ORM\Query\Expr::mod() (#8377)
* Add Doctrine\ORM\Query\Expr::mod()

Co-authored-by: Menno Holtkamp <menno.holtkamp@shopforce.nl>

* [GH-6739] Add entry to documentation

Co-authored-by: Menno Holtkamp <menno.holtkamp@shopforce.nl>
2020-12-06 23:09:20 +01:00
1563 changed files with 64373 additions and 38447 deletions

View File

@@ -7,26 +7,74 @@
"versions": [
{
"name": "3.0",
"branchName": "master",
"branchName": "3.0.x",
"slug": "latest",
"upcoming": true
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"name": "2.17",
"branchName": "2.17.x",
"slug": "2.17",
"upcoming": true
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"name": "2.16",
"branchName": "2.16.x",
"slug": "2.16",
"current": true,
"aliases": [
"current",
"stable"
]
},
{
"name": "2.15",
"branchName": "2.15.x",
"slug": "2.15",
"maintained": false
},
{
"name": "2.14",
"branchName": "2.14.x",
"slug": "2.14",
"maintained": false
},
{
"name": "2.13",
"branchName": "2.13.x",
"slug": "2.13",
"maintained": false
},
{
"name": "2.12",
"branchName": "2.12.x",
"slug": "2.12",
"maintained": false
},
{
"name": "2.11",
"branchName": "2.11.x",
"slug": "2.11",
"maintained": false
},
{
"name": "2.10",
"branchName": "2.10.x",
"slug": "2.10",
"maintained": false
},
{
"name": "2.9",
"branchName": "2.9.x",
"slug": "2.9",
"maintained": false
},
{
"name": "2.8",
"branchName": "2.8.x",
"slug": "2.8",
"maintained": false
},
{
"name": "2.7",
"branchName": "2.7",

13
.gitattributes vendored
View File

@@ -1,11 +1,11 @@
/.github export-ignore
/ci export-ignore
/docs export-ignore
/tests export-ignore
/tools export-ignore
/docs export-ignore
/.github export-ignore
.doctrine-project.json export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.gitmodules export-ignore
.travis.yml export-ignore
build.properties export-ignore
build.properties.dev export-ignore
build.xml export-ignore
@@ -15,4 +15,9 @@ run-all.sh export-ignore
phpcs.xml.dist export-ignore
phpbench.json export-ignore
phpstan.neon export-ignore
phpstan-baseline.neon export-ignore
phpstan-dbal2.neon export-ignore
phpstan-params.neon export-ignore
phpstan-persistence2.neon export-ignore
psalm.xml export-ignore
psalm-baseline.xml export-ignore

37
.github/ISSUE_TEMPLATE/BC_Break.md vendored Normal file
View File

@@ -0,0 +1,37 @@
---
name: 💥 BC Break
about: Have you encountered an issue during upgrade? 💣
---
<!--
Before reporting a BC break, please consult the upgrading document to make sure it's not an expected change: https://github.com/doctrine/orm/blob/2.9.x/UPGRADE.md
-->
### BC Break Report
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| BC Break | yes
| Version | x.y.z
#### Summary
<!-- Provide a summary describing the problem you are experiencing. -->
#### Previous behavior
<!-- What was the previous (working) behavior? -->
#### Current behavior
<!-- What is the current (broken) behavior? -->
#### How to reproduce
<!--
Provide steps to reproduce the BC break.
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
Adding a failing Unit or Functional Test would help us a lot - you can submit it in a Pull Request separately, referencing this bug report.
-->

34
.github/ISSUE_TEMPLATE/Bug.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: 🐞 Bug Report
about: Something is broken? 🔨
---
### Bug Report
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| BC Break | yes/no
| Version | x.y.z
#### Summary
<!-- Provide a summary describing the problem you are experiencing. -->
#### Current behavior
<!-- What is the current (buggy) behavior? -->
#### How to reproduce
<!--
Provide steps to reproduce the bug.
If possible, also add a code snippet with relevant configuration, entity mappings, DQL etc.
Adding a failing Unit or Functional Test would help us a lot - you can submit one in a Pull Request separately, referencing this bug report.
-->
#### Expected behavior
<!-- What was the expected (correct) behavior? -->

View File

@@ -0,0 +1,18 @@
---
name: 🎉 Feature Request
about: You have a neat idea that should be implemented? 🎩
---
### Feature Request
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| New Feature | yes
| RFC | yes/no
| BC Break | yes/no
#### Summary
<!-- Provide a summary of the feature you would like to see implemented. -->

View File

@@ -0,0 +1,6 @@
---
name: ❓ Support Question
about: Have a problem that you can't figure out? 🤔
---
Please use https://github.com/doctrine/orm/discussions instead.

View File

@@ -0,0 +1,19 @@
---
name: 🐞 Failing Test
about: You found a bug and have a failing Unit or Functional test? 🔨
---
### Failing Test
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| BC Break | yes/no
| Version | x.y.z
#### Summary
<!-- Provide a summary of the failing scenario. -->

View File

@@ -0,0 +1,18 @@
---
name: ⚙ Improvement
about: You have some improvement to make Doctrine better? 🎁
---
### Improvement
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| New Feature | yes
| RFC | yes/no
| BC Break | yes/no
#### Summary
<!-- Provide a summary of the improvement you are submitting. -->

View File

@@ -0,0 +1,26 @@
---
name: 🎉 New Feature
about: You have implemented some neat idea that you want to make part of Doctrine? 🎩
---
<!--
Thank you for submitting new feature!
Pick the target branch based according to these criteria:
* submitting a bugfix: target the lowest active stable branch: 2.9.x
* submitting a new feature: target the next minor branch: 2.10.x
* submitting a BC-breaking change: target the next major branch: 3.0.x
-->
### New Feature
<!-- Fill in the relevant information below to help triage your issue. -->
| Q | A
|------------ | ------
| New Feature | yes
| RFC | yes/no
| BC Break | yes/no
#### Summary
<!-- Provide a summary of the feature you have implemented. -->

View File

@@ -1,43 +0,0 @@
name: "Coding Standards"
on:
pull_request:
jobs:
coding-standards:
name: "Coding Standards"
runs-on: "ubuntu-latest"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
with:
fetch-depth: 10
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: "cs2pr"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
- name: "Install diff-sniffer"
run: "wget https://github.com/diff-sniffer/diff-sniffer/releases/download/0.5.1/diff-sniffer.phar"
- name: "Fetch head branch"
run: "git remote set-branches --add origin $GITHUB_BASE_REF && git fetch origin $GITHUB_BASE_REF"
- name: "Run diff-sniffer"
run: "php diff-sniffer.phar origin/$GITHUB_BASE_REF...$GITHUB_SHA --report=checkstyle | cs2pr"
- name: "Run phpcbf"
run: "vendor/bin/phpcbf"

27
.github/workflows/coding-standards.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: "Coding Standards"
on:
pull_request:
branches:
- "*.x"
paths:
- .github/workflows/coding-standards.yml
- bin/**
- composer.*
- lib/**
- phpcs.xml.dist
- tests/**
push:
branches:
- "*.x"
paths:
- .github/workflows/coding-standards.yml
- bin/**
- composer.*
- lib/**
- phpcs.xml.dist
- tests/**
jobs:
coding-standards:
uses: "doctrine/.github/.github/workflows/coding-standards.yml@3.0.0"

View File

@@ -2,7 +2,25 @@ name: "Continuous Integration"
on:
pull_request:
branches:
- "*.x"
paths:
- .github/workflows/continuous-integration.yml
- ci/**
- composer.*
- lib/**
- phpunit.xml.dist
- tests/**
push:
branches:
- "*.x"
paths:
- .github/workflows/continuous-integration.yml
- ci/**
- composer.*
- lib/**
- phpunit.xml.dist
- tests/**
env:
fail-fast: true
@@ -10,7 +28,7 @@ env:
jobs:
phpunit-smoke-check:
name: "PHPUnit with SQLite"
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-22.04"
strategy:
matrix:
@@ -19,15 +37,32 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
deps:
- "highest"
- "8.1"
- "8.2"
dbal-version:
- "default"
extension:
- "pdo_sqlite"
proxy:
- "common"
include:
- deps: "lowest"
php-version: "7.3"
- php-version: "8.0"
dbal-version: "2.13"
extension: "pdo_sqlite"
- php-version: "8.2"
dbal-version: "3@dev"
extension: "pdo_sqlite"
- php-version: "8.2"
dbal-version: "default"
extension: "sqlite3"
- php-version: "8.1"
dbal-version: "default"
proxy: "lazy-ghost"
extension: "pdo_sqlite"
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -35,44 +70,64 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
extensions: "pdo, pdo_sqlite"
extensions: "apcu, pdo, ${{ matrix.extension }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "${{ matrix.deps }}"
composer-options: "--ignore-platform-req=php+"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --coverage-clover=coverage-no-cache.xml"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 0
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
- name: "Run PHPUnit with Second Level Cache"
run: "vendor/bin/phpunit -c ci/github/phpunit/sqlite.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --exclude-group performance,non-cacheable,locking_functional --coverage-clover=coverage-cache.xml"
env:
ENABLE_SECOND_LEVEL_CACHE: 1
ORM_PROXY_IMPLEMENTATION: "${{ matrix.proxy }}"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "phpunit-sqlite-${{ matrix.deps }}-${{ matrix.php-version }}-coverage"
name: "phpunit-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage*.xml"
phpunit-postgres:
name: "PHPUnit with PostgreSQL"
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
- "8.2"
dbal-version:
- "default"
- "3@dev"
postgres-version:
- "9.6"
- "13"
- "15"
extension:
- pdo_pgsql
- pgsql
include:
- php-version: "8.0"
dbal-version: "2.13"
postgres-version: "14"
extension: pdo_pgsql
- php-version: "8.2"
dbal-version: "default"
postgres-version: "9.6"
extension: pdo_pgsql
services:
postgres:
@@ -88,7 +143,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -96,36 +151,51 @@ jobs:
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
extensions: "pgsql pdo_pgsql"
coverage: "pcov"
ini-values: "zend.assertions=1"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_pgsql.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-coverage"
name: "${{ github.job }}-${{ matrix.postgres-version }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage.xml"
phpunit-mariadb:
name: "PHPUnit with MariaDB"
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
- "8.2"
dbal-version:
- "default"
- "3@dev"
mariadb-version:
- "10.5"
- "10.9"
extension:
- "mysqli"
- "pdo_mysql"
include:
- php-version: "8.0"
dbal-version: "2.13"
mariadb-version: "10.6"
extension: "pdo_mysql"
services:
mariadb:
@@ -142,46 +212,60 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
ini-values: "zend.assertions=1, apc.enable_cli=1"
extensions: "${{ matrix.extension }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage.xml"
- name: "Upload coverage file"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
name: "${{ github.job }}-${{ matrix.mariadb-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage.xml"
phpunit-mysql:
name: "PHPUnit with MySQL"
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-22.04"
needs: "phpunit-smoke-check"
strategy:
matrix:
php-version:
- "7.4"
- "8.2"
dbal-version:
- "default"
- "3@dev"
mysql-version:
- "5.7"
- "8.0"
extension:
- "mysqli"
- "pdo_mysql"
include:
- php-version: "8.0"
dbal-version: "2.13"
mysql-version: "8.0"
extension: "pdo_mysql"
services:
mysql:
@@ -197,7 +281,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
@@ -206,11 +290,17 @@ jobs:
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1"
ini-values: "zend.assertions=1, apc.enable_cli=1"
extensions: "${{ matrix.extension }}"
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
composer-options: "--ignore-platform-req=php+"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/${{ matrix.extension }}.xml --coverage-clover=coverage-no-cache.xml"
@@ -223,14 +313,48 @@ jobs:
ENABLE_SECOND_LEVEL_CACHE: 1
- name: "Upload coverage files"
uses: "actions/upload-artifact@v2"
uses: "actions/upload-artifact@v3"
with:
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-coverage"
name: "${{ github.job }}-${{ matrix.mysql-version }}-${{ matrix.extension }}-${{ matrix.php-version }}-${{ matrix.dbal-version }}-coverage"
path: "coverage*.xml"
phpunit-lower-php-versions:
name: "PHPUnit with SQLite"
runs-on: "ubuntu-22.04"
strategy:
matrix:
php-version:
- "7.1"
deps:
- "highest"
- "lowest"
steps:
- name: "Checkout"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "${{ matrix.deps }}"
- name: "Run PHPUnit"
run: "vendor/bin/phpunit -c ci/github/phpunit/pdo_sqlite.xml"
upload_coverage:
name: "Upload coverage to Codecov"
runs-on: "ubuntu-20.04"
runs-on: "ubuntu-22.04"
needs:
- "phpunit-smoke-check"
- "phpunit-postgres"
@@ -239,16 +363,16 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
- name: "Download coverage files"
uses: "actions/download-artifact@v2"
uses: "actions/download-artifact@v3"
with:
path: "reports"
- name: "Upload to Codecov"
uses: "codecov/codecov-action@v1"
uses: "codecov/codecov-action@v3"
with:
directory: reports

51
.github/workflows/documentation.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: "Documentation"
on:
pull_request:
branches:
- "*.x"
paths:
- .github/workflows/documentation.yml
- docs/**
push:
branches:
- "*.x"
paths:
- .github/workflows/documentation.yml
- docs/**
jobs:
validate-with-guides:
name: "Validate documentation with phpDocumentor/guides"
runs-on: "ubuntu-22.04"
steps:
- name: "Checkout code"
uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "8.2"
- name: "Remove existing composer file"
run: "rm composer.json"
- name: "Require phpdocumentor/guides-cli"
run: "composer require --dev phpdocumentor/guides-cli dev-main@dev --no-update"
- name: "Configure minimum stability"
run: "composer config minimum-stability dev"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"
- name: "Add dummy title to the sidebar"
run: |
printf '%s\n%s\n\n%s\n' "Dummy title" "===========" "$(cat docs/en/sidebar.rst)" > docs/en/sidebar.rst
- name: "Run guides-cli"
run: "vendor/bin/guides -vvv --no-progress docs/en /tmp/test 2>&1 | ( ! grep WARNING )"

61
.github/workflows/phpbench.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: "Performance benchmark"
on:
pull_request:
branches:
- "*.x"
paths:
- .github/workflows/phpbench.yml
- composer.*
- lib/**
- phpbench.json
- tests/**
push:
branches:
- "*.x"
paths:
- .github/workflows/phpbench.yml
- composer.*
- lib/**
- phpbench.json
- tests/**
env:
fail-fast: true
jobs:
phpbench:
name: "PHPBench"
runs-on: "ubuntu-22.04"
strategy:
matrix:
php-version:
- "7.4"
steps:
- name: "Checkout"
uses: "actions/checkout@v3"
with:
fetch-depth: 2
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
php-version: "${{ matrix.php-version }}"
coverage: "pcov"
ini-values: "zend.assertions=1, apc.enable_cli=1"
- name: "Cache dependencies installed with composer"
uses: "actions/cache@v3"
with:
path: "~/.composer/cache"
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
- name: "Install dependencies with composer"
run: "composer update --no-interaction --no-progress"
- name: "Run PHPBench"
run: "vendor/bin/phpbench run --report=default"

View File

@@ -7,40 +7,9 @@ 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"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:release"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
"SHELL_VERBOSITY": "3"
- name: "Create Merge-Up Pull Request"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-merge-up-pull-request"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
- name: "Create new milestones"
uses: "laminas/automatic-releases@v1"
with:
command-name: "laminas:automatic-releases:create-milestones"
env:
"GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }}
"SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }}
"GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }}
"GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }}
uses: "doctrine/.github/.github/workflows/release-on-milestone-closed.yml@3.0.0"
secrets:
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 }}

View File

@@ -1,56 +1,103 @@
name: Static Analysis
name: "Static Analysis"
on:
pull_request:
branches:
- "*.x"
paths:
- .github/workflows/static-analysis.yml
- composer.*
- lib/**
- phpstan*
- psalm*
- tests/Doctrine/StaticAnalysis/**
push:
branches:
- "*.x"
paths:
- .github/workflows/static-analysis.yml
- composer.*
- lib/**
- phpstan*
- psalm*
- tests/Doctrine/StaticAnalysis/**
jobs:
static-analysis-phpstan:
name: "PHPStan"
runs-on: "ubuntu-latest"
name: "Static Analysis with PHPStan"
runs-on: "ubuntu-22.04"
strategy:
fail-fast: false
matrix:
php-version:
- "7.4"
dbal-version:
- "default"
persistence-version:
- "default"
include:
- dbal-version: "2.13"
persistence-version: "default"
- dbal-version: "default"
persistence-version: "2.5"
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
tools: cs2pr
php-version: "8.2"
- name: "Require specific DBAL version"
run: "composer require doctrine/dbal ^${{ matrix.dbal-version }} --no-update"
if: "${{ matrix.dbal-version != 'default' }}"
- name: "Require specific persistence version"
run: "composer require doctrine/persistence ^$([ ${{ matrix.persistence-version }} = default ] && echo '3.1' || echo ${{ matrix.persistence-version }}) --no-update"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"
- name: "Run a static analysis with phpstan/phpstan"
run: "php vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr"
run: "vendor/bin/phpstan analyse"
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version == 'default'}}"
- name: "Run a static analysis with phpstan/phpstan"
run: "vendor/bin/phpstan analyse -c phpstan-dbal2.neon"
if: "${{ matrix.dbal-version == '2.13' }}"
- name: "Run a static analysis with phpstan/phpstan"
run: "vendor/bin/phpstan analyse -c phpstan-persistence2.neon"
if: "${{ matrix.dbal-version == 'default' && matrix.persistence-version != 'default'}}"
static-analysis-psalm:
name: "Psalm"
runs-on: "ubuntu-latest"
name: "Static Analysis with Psalm"
runs-on: "ubuntu-22.04"
strategy:
matrix:
php-version:
- "7.4"
fail-fast: false
steps:
- name: "Checkout code"
uses: "actions/checkout@v2"
uses: "actions/checkout@v3"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "${{ matrix.php-version }}"
php-version: "8.2"
- name: "Require specific persistence version"
run: "composer require doctrine/persistence ^3.1 --no-update"
- name: "Install dependencies with Composer"
uses: "ramsey/composer-install@v1"
uses: "ramsey/composer-install@v2"
with:
dependency-versions: "highest"
- name: "Run a static analysis with vimeo/psalm"
run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"

4
.gitignore vendored
View File

@@ -15,4 +15,6 @@ vendor/
/tests/Doctrine/Performance/history.db
/.phpcs-cache
composer.lock
/.phpunit.result.cache
.phpunit.cache
.phpunit.result.cache
/*.phpunit.xml

View File

@@ -6,30 +6,17 @@ Before we can merge your Pull-Request here are some guidelines that you need to
These guidelines exist not to annoy you, but to keep the code base clean,
unified and future proof.
## We only accept PRs to "master"
Doctrine has [general contributing guidelines][contributor workflow], make
sure you follow them.
Our branching strategy is "everything to master first", even
bugfixes and we then merge them into the stable branches. You should only
open pull requests against the master branch. Otherwise we cannot accept the PR.
There is one exception to the rule, when we merged a bug into some stable branches
we do occasionally accept pull requests that merge the same bug fix into earlier
branches.
[contributor workflow]: https://www.doctrine-project.org/contribute/index.html
## Coding Standard
We use PSR-1 and PSR-2:
This project follows [`doctrine/coding-standard`][coding standard homepage].
You may fix many some of the issues with `vendor/bin/phpcbf`.
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
with some exceptions/differences:
* Keep the nesting of control structures per method as small as possible
* Align equals (=) signs
* Add spaces between assignment, control and return statements
* Prefer early exit over nesting conditions
* Add spaces around a negation if condition ``if ( ! $cond)``
[coding standard homepage]: https://github.com/doctrine/coding-standard
## Unit-Tests
@@ -50,31 +37,29 @@ will have to run a composer installation in the project:
```sh
git clone git@github.com:doctrine/orm.git
cd orm
curl -sS https://getcomposer.org/installer | php --
./composer.phar install
composer install
```
You will also need to enable the PHP extension that provides the SQLite driver
for PDO: `pdo_sqlite`. How to do so depends on your system, but checking that it
is enabled can universally be done with `php -m`: that command should list the
extension.
To run the testsuite against another database, copy the ``phpunit.xml.dist``
to for example ``mysql.phpunit.xml`` and edit the parameters. You can
take a look at the ``tests/travis`` folder for some examples. Then run:
take a look at the ``ci/github/phpunit`` directory for some examples. Then run:
vendor/bin/phpunit -c mysql.phpunit.xml
If you do not provide these parameters, the test suite will use an in-memory
sqlite database.
Tips for creating unit tests:
1. If you put a test into the `Ticket` namespace as described above, put the testcase and all entities into the same class.
See `https://github.com/doctrine/orm/tree/master/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
See `https://github.com/doctrine/orm/tree/2.8.x/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2306Test.php` for an
example.
## Travis
We automatically run your pull request through [Travis CI](http://www.travis-ci.org)
against SQLite, MySQL and PostgreSQL. If you break the tests, we cannot merge your code,
so please make sure that your code is working before opening up a Pull-Request.
## Getting merged
Please allow us time to review your pull requests. We will give our best to review

View File

@@ -1,4 +1,4 @@
Copyright (c) 2006-2015 Doctrine Project
Copyright (c) Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -1,9 +1,11 @@
| [Master][Master] | [2.8.x][2.8] |
|:----------------:|:----------:|
| [![Build status][Master image]][Master] | [![Build status][2.8 image]][2.8] |
| [![Coverage Status][Master coverage image]][Master coverage] | [![Coverage Status][2.8 coverage image]][2.8 coverage] |
| [3.0.x][3.0] | [2.16.x][2.16] | [2.15.x][2.15] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.16 image]][2.16] | [![Build status][2.15 image]][2.15] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.16 coverage image]][2.16 coverage] | [![Coverage Status][2.15 coverage image]][2.15 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
[<h1 align="center">🇺🇦 UKRAINE NEEDS YOUR HELP NOW!</h1>](https://www.doctrine-project.org/stop-war.html)
Doctrine ORM is an object-relational mapper for PHP 7.1+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL),
inspired by Hibernate's HQL. This provides developers with a powerful alternative to SQL that maintains flexibility
@@ -13,14 +15,18 @@ without requiring unnecessary code duplication.
## More resources:
* [Website](http://www.doctrine-project.org)
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/latest/index.html)
* [Documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/index.html)
[Master image]: https://img.shields.io/travis/doctrine/orm/master.svg?style=flat-square
[Master]: https://travis-ci.org/doctrine/orm
[Master coverage image]: https://codecov.io/gh/doctrine/orm/branch/master/graph/badge.svg
[Master coverage]: https://codecov.io/gh/doctrine/orm/branch/master
[2.8 image]: https://img.shields.io/travis/doctrine/orm/2.8.svg?style=flat-square
[2.8]: https://github.com/doctrine/orm/tree/2.8
[2.8 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.8/graph/badge.svg
[2.8 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.8
[3.0 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0.x
[3.0]: https://github.com/doctrine/orm/tree/3.0.x
[3.0 coverage image]: https://codecov.io/gh/doctrine/orm/branch/3.0.x/graph/badge.svg
[3.0 coverage]: https://codecov.io/gh/doctrine/orm/branch/3.0.x
[2.16 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.16.x
[2.16]: https://github.com/doctrine/orm/tree/2.16.x
[2.16 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.16.x/graph/badge.svg
[2.16 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.16.x
[2.15 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.15.x
[2.15]: https://github.com/doctrine/orm/tree/2.15.x
[2.15 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.15.x/graph/badge.svg
[2.15 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.15.x

View File

@@ -10,8 +10,8 @@ we cannot protect you from SQL injection.
Please read the documentation chapter on Security in Doctrine DBAL and ORM to
understand the assumptions we make.
- [DBAL Security Page](https://github.com/doctrine/dbal/blob/master/docs/en/reference/security.rst)
- [ORM Security Page](https://github.com/doctrine/orm/blob/master/docs/en/reference/security.rst)
- [DBAL Security Page](https://www.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/security.html)
- [ORM Security Page](https://www.doctrine-project.org/projects/doctrine-orm/en/stable/reference/security.html)
If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core

View File

@@ -1,3 +1,639 @@
# Upgrade to 2.16
## Deprecated accepting duplicate IDs in the identity map
For any given entity class and ID value, there should be only one object instance
representing the entity.
In https://github.com/doctrine/orm/pull/10785, a check was added that will guard this
in the identity map. The most probable cause for violations of this rule are collisions
of application-provided IDs.
In ORM 2.16.0, the check was added by throwing an exception. In ORM 2.16.1, this will be
changed to a deprecation notice. ORM 3.0 will make it an exception again. Use
`\Doctrine\ORM\Configuration::setRejectIdCollisionInIdentityMap()` if you want to opt-in
to the new mode.
## Potential changes to the order in which `INSERT`s are executed
In https://github.com/doctrine/orm/pull/10547, the commit order computation was improved
to fix a series of bugs where a correct (working) commit order was previously not found.
Also, the new computation may get away with fewer queries being executed: By inserting
referred-to entities first and using their ID values for foreign key fields in subsequent
`INSERT` statements, additional `UPDATE` statements that were previously necessary can be
avoided.
When using database-provided, auto-incrementing IDs, this may lead to IDs being assigned
to entities in a different order than it was previously the case.
## Deprecated `\Doctrine\ORM\Internal\CommitOrderCalculator` and related classes
With changes made to the commit order computation, the internal classes
`\Doctrine\ORM\Internal\CommitOrderCalculator`, `\Doctrine\ORM\Internal\CommitOrder\Edge`,
`\Doctrine\ORM\Internal\CommitOrder\Vertex` and `\Doctrine\ORM\Internal\CommitOrder\VertexState`
have been deprecated and will be removed in ORM 3.0.
## Deprecated returning post insert IDs from `EntityPersister::executeInserts()`
Persisters implementing `\Doctrine\ORM\Persisters\Entity\EntityPersister` should no longer
return an array of post insert IDs from their `::executeInserts()` method. Make the
persister call `Doctrine\ORM\UnitOfWork::assignPostInsertId()` instead.
## Changing the way how reflection-based mapping drivers report fields, deprecated the "old" mode
In ORM 3.0, a change will be made regarding how the `AttributeDriver` reports field mappings.
This change is necessary to be able to detect (and reject) some invalid mapping configurations.
To avoid surprises during 2.x upgrades, the new mode is opt-in. It can be activated on the
`AttributeDriver` and `AnnotationDriver` by setting the `$reportFieldsWhereDeclared`
constructor parameter to `true`. It will cause `MappingException`s to be thrown when invalid
configurations are detected.
Not enabling the new mode will cause a deprecation notice to be raised. In ORM 3.0,
only the new mode will be available.
# Upgrade to 2.15
## Deprecated configuring `JoinColumn` on the inverse side of one-to-one associations
For one-to-one associations, the side using the `mappedBy` attribute is the inverse side.
The owning side is the entity with the table containing the foreign key. Using `JoinColumn`
configuration on the _inverse_ side now triggers a deprecation notice and will be an error
in 3.0.
## Deprecated overriding fields or associations not declared in mapped superclasses
As stated in the documentation, fields and associations may only be overridden when being inherited
from mapped superclasses. Overriding them for parent entity classes now triggers a deprecation notice
and will be an error in 3.0.
## Deprecated undeclared entity inheritance
As soon as an entity class inherits from another entity class, inheritance has to
be declared by adding the appropriate configuration for the root entity.
## Deprecated stubs for "concrete table inheritance"
This third way of mapping class inheritance was never implemented. Code stubs are
now deprecated and will be removed in 3.0.
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::INHERITANCE_TYPE_TABLE_PER_CLASS` constant
* `\Doctrine\ORM\Mapping\ClassMetadataInfo::isInheritanceTypeTablePerClass()` method
* Using `TABLE_PER_CLASS` as the value for the `InheritanceType` attribute or annotation
or in XML configuration files.
# Upgrade to 2.14
## Deprecated `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byName($field)` method.
Use `Doctrine\ORM\Persisters\Exception\UnrecognizedField::byFullyQualifiedName($className, $field)` instead.
## Deprecated constants of `Doctrine\ORM\Internal\CommitOrderCalculator`
The following public constants have been deprecated:
* `CommitOrderCalculator::NOT_VISITED`
* `CommitOrderCalculator::IN_PROGRESS`
* `CommitOrderCalculator::VISITED`
These constants were used for internal purposes. Relying on them is discouraged.
## Deprecated `Doctrine\ORM\Query\AST\InExpression`
The AST parser will create a `InListExpression` or a `InSubselectExpression` when
encountering an `IN ()` DQL expression instead of a generic `InExpression`.
As a consequence, `SqlWalker::walkInExpression()` has been deprecated in favor of
`SqlWalker::walkInListExpression()` and `SqlWalker::walkInSubselectExpression()`.
## Deprecated constructing a `CacheKey` without `$hash`
The `Doctrine\ORM\Cache\CacheKey` class has an explicit constructor now with
an optional parameter `$hash`. That parameter will become mandatory in 3.0.
## Deprecated `AttributeDriver::$entityAnnotationClasses`
If you need to change the behavior of `AttributeDriver::isTransient()`,
override that method instead.
## Deprecated incomplete schema updates
Using `orm:schema-tool:update` without passing the `--complete` flag is
deprecated. Use schema asset filtering if you need to preserve assets not
managed by DBAL.
Likewise, calling `SchemaTool::updateSchema()` or
`SchemaTool::getUpdateSchemaSql()` with a second argument is deprecated.
## Deprecated annotation mapping driver.
Please switch to one of the other mapping drivers. Native attributes which PHP
supports since version 8.0 are probably your best option.
As a consequence, the following methods are deprecated:
- `ORMSetup::createAnnotationMetadataConfiguration`
- `ORMSetup::createDefaultAnnotationDriver`
The marker interface `Doctrine\ORM\Mapping\Annotation` is deprecated as well.
All annotation/attribute classes implement
`Doctrine\ORM\Mapping\MappingAttribute` now.
## Deprecated `Doctrine\ORM\Proxy\Proxy` interface.
Use `Doctrine\Persistence\Proxy` instead to check whether proxies are initialized.
## Deprecated `Doctrine\ORM\Event\LifecycleEventArgs` class.
It will be removed in 3.0. Use one of the dedicated event classes instead:
* `Doctrine\ORM\Event\PrePersistEventArgs`
* `Doctrine\ORM\Event\PreUpdateEventArgs`
* `Doctrine\ORM\Event\PreRemoveEventArgs`
* `Doctrine\ORM\Event\PostPersistEventArgs`
* `Doctrine\ORM\Event\PostUpdateEventArgs`
* `Doctrine\ORM\Event\PostRemoveEventArgs`
* `Doctrine\ORM\Event\PostLoadEventArgs`
# Upgrade to 2.13
## Deprecated `EntityManager::create()`
The constructor of `EntityManager` is now public and should be used instead of the `create()` method.
However, the constructor expects a `Connection` while `create()` accepted an array with connection parameters.
You can pass that array to DBAL's `Doctrine\DBAL\DriverManager::getConnection()` method to bootstrap the
connection.
## Deprecated `QueryBuilder` methods and constants.
1. The `QueryBuilder::getState()` method has been deprecated as the builder state is an internal concern.
2. Relying on the type of the query being built by using `QueryBuilder::getType()` has been deprecated.
If necessary, track the type of the query being built outside of the builder.
The following `QueryBuilder` constants related to the above methods have been deprecated:
1. `SELECT`,
2. `DELETE`,
3. `UPDATE`,
4. `STATE_DIRTY`,
5. `STATE_CLEAN`.
## Deprecated omitting only the alias argument for `QueryBuilder::update` and `QueryBuilder::delete`
When building an UPDATE or DELETE query and when passing a class/type to the function, the alias argument must not be omitted.
### Before
```php
$qb = $em->createQueryBuilder()
->delete('User u')
->where('u.id = :user_id')
->setParameter('user_id', 1);
```
### After
```php
$qb = $em->createQueryBuilder()
->delete('User', 'u')
->where('u.id = :user_id')
->setParameter('user_id', 1);
```
## Deprecated using the `IDENTITY` identifier strategy on platform that do not support identity columns
If identity columns are emulated with sequences on the platform you are using,
you should switch to the `SEQUENCE` strategy.
## Deprecated passing `null` to `Doctrine\ORM\Query::setFirstResult()`
`$query->setFirstResult(null);` is equivalent to `$query->setFirstResult(0)`.
## Deprecated calling setters without arguments
The following methods will require an argument in 3.0. Pass `null` instead of
omitting the argument.
* `Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs::setFoundMetadata()`
* `Doctrine\ORM\AbstractQuery::setHydrationCacheProfile()`
* `Doctrine\ORM\AbstractQuery::setResultCache()`
* `Doctrine\ORM\AbstractQuery::setResultCacheProfile()`
## Deprecated passing invalid fetch modes to `AbstractQuery::setFetchMode()`
Calling `AbstractQuery::setFetchMode()` with anything else than
`Doctrine\ORM\Mapping::FETCH_EAGER` results in
`Doctrine\ORM\Mapping::FETCH_LAZY` being used. Relying on that behavior is
deprecated and will result in an exception in 3.0.
## Deprecated `getEntityManager()` in `Doctrine\ORM\Event\OnClearEventArgs` and `Doctrine\ORM\Event\*FlushEventArgs`
This method has been deprecated in:
* `Doctrine\ORM\Event\OnClearEventArgs`
* `Doctrine\ORM\Event\OnFlushEventArgs`
* `Doctrine\ORM\Event\PostFlushEventArgs`
* `Doctrine\ORM\Event\PreFlushEventArgs`
It will be removed in 3.0. Use `getObjectManager()` instead.
## Prepare split of output walkers and tree walkers
In 3.0, `SqlWalker` and its child classes won't implement the `TreeWalker`
interface anymore. Relying on that inheritance is deprecated.
The following methods of the `TreeWalker` interface have been deprecated:
* `setQueryComponent()`
* `walkSelectClause()`
* `walkFromClause()`
* `walkFunction()`
* `walkOrderByClause()`
* `walkOrderByItem()`
* `walkHavingClause()`
* `walkJoin()`
* `walkSelectExpression()`
* `walkQuantifiedExpression()`
* `walkSubselect()`
* `walkSubselectFromClause()`
* `walkSimpleSelectClause()`
* `walkSimpleSelectExpression()`
* `walkAggregateExpression()`
* `walkGroupByClause()`
* `walkGroupByItem()`
* `walkDeleteClause()`
* `walkUpdateClause()`
* `walkUpdateItem()`
* `walkWhereClause()`
* `walkConditionalExpression()`
* `walkConditionalTerm()`
* `walkConditionalFactor()`
* `walkConditionalPrimary()`
* `walkExistsExpression()`
* `walkCollectionMemberExpression()`
* `walkEmptyCollectionComparisonExpression()`
* `walkNullComparisonExpression()`
* `walkInExpression()`
* `walkInstanceOfExpression()`
* `walkLiteral()`
* `walkBetweenExpression()`
* `walkLikeExpression()`
* `walkStateFieldPathExpression()`
* `walkComparisonExpression()`
* `walkInputParameter()`
* `walkArithmeticExpression()`
* `walkArithmeticTerm()`
* `walkStringPrimary()`
* `walkArithmeticFactor()`
* `walkSimpleArithmeticExpression()`
* `walkPathExpression()`
* `walkResultVariable()`
* `getExecutor()`
The following changes have been made to the abstract `TreeWalkerAdapter` class:
* All implementations of now-deprecated `TreeWalker` methods have been
deprecated as well.
* The method `setQueryComponent()` will become protected in 3.0. Calling it
publicly is deprecated.
* The method `_getQueryComponents()` is deprecated, call `getQueryComponents()`
instead.
On the `TreeWalkerChain` class, all implementations of now-deprecated
`TreeWalker` methods have been deprecated as well. However, `SqlWalker` is
unaffected by those deprecations and will continue to implement all of those
methods.
## Deprecated passing `null` to `Doctrine\ORM\Query::setDQL()`
Doing `$query->setDQL(null);` achieves nothing.
## Deprecated omitting second argument to `NamingStrategy::joinColumnName`
When implementing `NamingStrategy`, it is deprecated to implement
`joinColumnName()` with only one argument.
### Before
```php
<?php
class MyStrategy implements NamingStrategy
{
/**
* @param string $propertyName A property name.
*/
public function joinColumnName($propertyName): string
{
// …
}
}
```
### After
For backward-compatibility reasons, the parameter has to be optional, but can
be documented as guaranteed to be a `class-string`.
```php
<?php
class MyStrategy implements NamingStrategy
{
/**
* @param string $propertyName A property name.
* @param class-string $className
*/
public function joinColumnName($propertyName, $className = null): string
{
// …
}
}
```
## Deprecated methods related to named queries
The following methods have been deprecated:
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryMapping()`
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryResultClassMapping()`
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryResultSetMapping()`
- `Doctrine\ORM\Query\ResultSetMappingBuilder::addNamedNativeQueryEntityResultMapping()`
## Deprecated classes related to Doctrine 1 and reverse engineering
The following classes have been deprecated:
- `Doctrine\ORM\Tools\ConvertDoctrine1Schema`
- `Doctrine\ORM\Tools\DisconnectedClassMetadataFactory`
## Deprecate `ClassMetadataInfo` usage
It is deprecated to pass `Doctrine\ORM\Mapping\ClassMetadataInfo` instances
that are not also instances of `Doctrine\ORM\ClassMetadata` to the following
methods:
- `Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder::__construct()`
- `Doctrine\ORM\Mapping\Driver\DatabaseDriver::loadMetadataForClass()`
- `Doctrine\ORM\Tools\SchemaValidator::validateClass()`
# Upgrade to 2.12
## Deprecated the `doctrine` binary.
The documentation explains how the console tools can be bootstrapped for
standalone usage.
The method `ConsoleRunner::printCliConfigTemplate()` is deprecated because it
was only useful in the context of the `doctrine` binary.
## Deprecate omitting `$class` argument to `ORMInvalidArgumentException::invalidIdentifierBindingEntity()`
To make it easier to identify understand the cause for that exception, it is
deprecated to omit the class name when calling
`ORMInvalidArgumentException::invalidIdentifierBindingEntity()`.
## Deprecate `Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper`
Using a console helper to provide the ORM's console commands with one or
multiple entity managers had been deprecated with 2.9 already. This leaves
The `EntityManagerHelper` class with no purpose which is why it is now
deprecated too. Applications that still rely on the `em` console helper, can
easily recreate that class in their own codebase.
## Deprecate custom repository classes that don't extend `EntityRepository`
Although undocumented, it is currently possible to configure a custom repository
class that implements `ObjectRepository` but does not extend the
`EntityRepository` base class.
This is now deprecated. Please extend `EntityRepository` instead.
## Deprecated more APIs related to entity namespace aliases
```diff
-$config = $entityManager->getConfiguration();
-$config->addEntityNamespace('CMS', 'My\App\Cms');
+use My\App\Cms\CmsUser;
-$entityManager->getRepository('CMS:CmsUser');
+$entityManager->getRepository(CmsUser::class);
```
## Deprecate `AttributeDriver::getReader()` and `AnnotationDriver::getReader()`
That method was inherited from the abstract `AnnotationDriver` class of
`doctrine/persistence`, and does not seem to serve any purpose.
## Un-deprecate `Doctrine\ORM\Proxy\Proxy`
Because no forward-compatible new proxy solution had been implemented yet, the
current proxy mechanism is not considered deprecated anymore for the time
being. This applies to the following interfaces/classes:
* `Doctrine\ORM\Proxy\Proxy`
* `Doctrine\ORM\Proxy\ProxyFactory`
These methods have been un-deprecated:
* `Doctrine\ORM\Configuration::getAutoGenerateProxyClasses()`
* `Doctrine\ORM\Configuration::getProxyDir()`
* `Doctrine\ORM\Configuration::getProxyNamespace()`
Note that the `Doctrine\ORM\Proxy\Autoloader` remains deprecated and will be removed in 3.0.
## Deprecate helper methods from `AbstractCollectionPersister`
The following protected methods of
`Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister`
are not in use anymore and will be removed.
* `evictCollectionCache()`
* `evictElementCache()`
## Deprecate `Doctrine\ORM\Query\TreeWalkerChainIterator`
This class won't have a replacement.
## Deprecate `OnClearEventArgs::getEntityClass()` and `OnClearEventArgs::clearsAllEntities()`
These methods will be removed in 3.0 along with the ability to partially clear
the entity manager.
## Deprecate `Doctrine\ORM\Configuration::newDefaultAnnotationDriver`
This functionality has been moved to the new `ORMSetup` class. Call
`Doctrine\ORM\ORMSetup::createDefaultAnnotationDriver()` to create
a new annotation driver.
## Deprecate `Doctrine\ORM\Tools\Setup`
In our effort to migrate from Doctrine Cache to PSR-6, the `Setup` class which
accepted a Doctrine Cache instance in each method has been deprecated.
The replacement is `Doctrine\ORM\ORMSetup` which accepts a PSR-6
cache instead.
## Deprecate `Doctrine\ORM\Cache\MultiGetRegion`
The interface will be merged with `Doctrine\ORM\Cache\Region` in 3.0.
# Upgrade to 2.11
## Rename `AbstractIdGenerator::generate()` to `generateId()`
Implementations of `AbstractIdGenerator` have to override the method
`generateId()` without calling the parent implementation. Not doing so is
deprecated. Calling `generate()` on any `AbstractIdGenerator` implementation
is deprecated.
## PSR-6-based second level cache
The second level cache has been reworked to consume a PSR-6 cache. Using a
Doctrine Cache instance is deprecated.
* `DefaultCacheFactory`: The constructor expects a PSR-6 cache item pool as
second argument now.
* `DefaultMultiGetRegion`: This class is deprecated in favor of `DefaultRegion`.
* `DefaultRegion`:
* The constructor expects a PSR-6 cache item pool as second argument now.
* The protected `$cache` property is deprecated.
* The properties `$name` and `$lifetime` as well as the constant
`REGION_KEY_SEPARATOR` and the method `getCacheEntryKey()` are flagged as
`@internal` now. They all will become `private` in 3.0.
* The method `getCache()` is deprecated without replacement.
## Deprecated: `Doctrine\ORM\Mapping\Driver\PHPDriver`
Use `StaticPHPDriver` instead when you want to programmatically configure
entity metadata.
You can convert mappings with the `orm:convert-mapping` command or more simply
in this case, `include` the metadata file from the `loadMetadata` static method
used by the `StaticPHPDriver`.
## Deprecated: `Setup::registerAutoloadDirectory()`
Use Composer's autoloader instead.
## Deprecated: `AbstractHydrator::hydrateRow()`
Following the deprecation of the method `AbstractHydrator::iterate()`, the
method `hydrateRow()` has been deprecated as well.
## Deprecate cache settings inspection
Doctrine does not provide its own cache implementation anymore and relies on
the PSR-6 standard instead. As a consequence, we cannot determine anymore
whether a given cache adapter is suitable for a production environment.
Because of that, functionality that aims to do so has been deprecated:
* `Configuration::ensureProductionSettings()`
* the `orm:ensure-production-settings` console command
# 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.
It is now deprecated to rely on:
- `Doctrine\ORM\Id\TableGenerator`;
- `Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_TABLE`;
- `Doctrine\ORM\Mapping\ClassMetadata::$tableGeneratorDefinition`;
- or `Doctrine\ORM\Mapping\ClassMetadata::isIdGeneratorTable()`.
## 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_.
Because of BC policy, the method does not exist on the interface yet. This is the example of safe usage:
```php
function foo(EntityManagerInterface $entityManager, callable $func) {
if (method_exists($entityManager, 'wrapInTransaction')) {
return $entityManager->wrapInTransaction($func);
}
return $entityManager->transactional($func);
}
```
`Doctrine\ORM\EntityManagerInterface#transactional()` has been deprecated.
## Minor BC BREAK: some exception methods have been removed
The following methods were not in use and are very unlikely to be used by
downstream packages or applications, and were consequently removed:
- `ORMException::entityMissingForeignAssignedId`
- `ORMException::entityMissingAssignedIdForField`
- `ORMException::invalidFlushMode`
## Deprecated: database-side UUID generation
[DB-generated UUIDs are deprecated as of `doctrine/dbal` 2.8][DBAL deprecation].
As a consequence, using the `UUID` strategy for generating identifiers is deprecated as well.
Furthermore, relying on the following classes and methods is deprecated:
- `Doctrine\ORM\Id\UuidGenerator`
- `Doctrine\ORM\Mapping\ClassMetadataInfo::isIdentifierUuid()`
[DBAL deprecation]: https://github.com/doctrine/dbal/pull/3212
## Minor BC BREAK: Custom hydrators and `toIterable()`
The type declaration of the `$stmt` parameter of `AbstractHydrator::toIterable()` has been removed. This change might
break custom hydrator implementations that override this very method.
Overriding this method is not recommended, which is why the method is documented as `@final` now.
```diff
- public function toIterable(ResultStatement $stmt, ResultSetMapping $resultSetMapping, array $hints = []): iterable
+ public function toIterable($stmt, ResultSetMapping $resultSetMapping, array $hints = []): iterable
```
## Deprecated: Entity Namespace Aliases
Entity namespace aliases are deprecated, use the magic ::class constant to abbreviate full class names
in EntityManager, EntityRepository and DQL.
```diff
- $entityManager->find('MyBundle:User', $id);
+ $entityManager->find(User::class, $id);
```
# Upgrade to 2.9
## Minor BC BREAK: Setup tool needs cache implementation
With the deprecation of doctrine/cache, the setup tool might no longer work as expected without a different cache
implementation. To work around this:
* Install symfony/cache: `composer require symfony/cache`. This will keep previous behaviour without any changes
* Instantiate caches yourself: to use a different cache implementation, pass a cache instance when calling any
configuration factory in the setup tool:
```diff
- $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, $proxyDir);
+ $cache = \Doctrine\Common\Cache\Psr6\DoctrineProvider::wrap($anyPsr6Implementation);
+ $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, $proxyDir, $cache);
```
* As a quick workaround, you can lock the doctrine/cache dependency to work around this: `composer require doctrine/cache ^1.11`.
Note that this is only recommended as a bandaid fix, as future versions of ORM will no longer work with doctrine/cache
1.11.
## Deprecated: doctrine/cache for metadata caching
The `Doctrine\ORM\Configuration#setMetadataCacheImpl()` method is deprecated and should no longer be used. Please use
`Doctrine\ORM\Configuration#setMetadataCache()` with any PSR-6 cache adapter instead.
## Removed: flushing metadata cache
To support PSR-6 caches, the `--flush` option for the `orm:clear-cache:metadata` command is ignored. Metadata cache is
now always cleared regardless of the cache adapter being used.
# Upgrade to 2.8
## Minor BC BREAK: Failed commit now throw OptimisticLockException
@@ -5,14 +641,19 @@
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#iterate()`
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
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
## Added `Doctrine\ORM\AbstractQuery#enableResultCache()` and `Doctrine\ORM\AbstractQuery#disableResultCache()` methods
Method `Doctrine\ORM\AbstractQuery#useResultCache()` which could be used for both enabling and disabling the cache
(depending on passed flag) was split into two.
(depending on passed flag) was split into two.
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
## Minor BC BREAK: paginator output walkers aren't be called anymore on sub-queries for queries without max results
To optimize DB interaction, `Doctrine\ORM\Tools\Pagination\Paginator` no longer fetches identifiers to be able to
perform the pagination with join collections when max results isn't set in the query.
@@ -31,7 +672,7 @@ In the last patch of the `v2.6.x` series, we fixed a bug that was not converting
In order to not break BC we've introduced a way to enable the fixed behavior using a boolean constructor argument. This
argument will be removed in 3.0 and the default behavior will be the fixed one.
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
## Deprecated: `Doctrine\ORM\AbstractQuery#useResultCache()`
Method `Doctrine\ORM\AbstractQuery#useResultCache()` is deprecated because it is split into `enableResultCache()`
and `disableResultCache()`. It will be removed in 3.0.
@@ -61,7 +702,7 @@ These related classes have been deprecated:
* `Doctrine\ORM\Proxy\ProxyFactory`
* `Doctrine\ORM\Proxy\Autoloader` - we suggest using the composer autoloader instead
These methods have been deprecated:
* `Doctrine\ORM\Configuration#getAutoGenerateProxyClasses()`
@@ -71,27 +712,18 @@ These methods have been deprecated:
## Deprecated `Doctrine\ORM\Version`
The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctrine ORM 3.0:
please refrain from checking the ORM version at runtime or use
[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/).
please refrain from checking the ORM version at runtime or use Composer's [runtime API](https://getcomposer.org/doc/07-runtime.md#knowing-whether-package-x-is-installed-in-version-y).
## Deprecated `EntityManager#merge()` and `EntityManager#detach()` methods
## Deprecated `EntityManager#merge()` method
Merge and detach semantics were a poor fit for the PHP "share-nothing" architecture.
In addition to that, merging/detaching caused multiple issues with data integrity
Merge semantics was a poor fit for the PHP "share-nothing" architecture.
In addition to that, merging caused multiple issues with data integrity
in the managed entity graph, which was constantly spawning more edge-case bugs/scenarios.
The following API methods were therefore deprecated:
* `EntityManager#merge()`
* `EntityManager#detach()`
* `UnitOfWork#merge()`
* `UnitOfWork#detach()`
Users are encouraged to migrate `EntityManager#detach()` calls to `EntityManager#clear()`.
In order to maintain performance on batch processing jobs, it is endorsed to enable
the second level cache (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
on entities that are frequently reused across multiple `EntityManager#clear()` calls.
An alternative to `EntityManager#merge()` will not be provided by ORM 3.0, since the merging
semantics should be part of the business domain rather than the persistence domain of an
@@ -119,7 +751,7 @@ If your code relies on single entity flushing optimisations via
Said API was affected by multiple data integrity bugs due to the fact
that change tracking was being restricted upon a subset of the managed
entities. The ORM cannot support committing subsets of the managed
entities. The ORM cannot support committing subsets of the managed
entities while also guaranteeing data integrity, therefore this
utility was removed.
@@ -134,8 +766,8 @@ If you would still like to perform batching operations over small `UnitOfWork`
instances, it is suggested to follow these paths instead:
* eagerly use `EntityManager#clear()` in conjunction with a specific second level
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html)
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/change-tracking-policies.html)
cache configuration (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/second-level-cache.html)
* use an explicit change tracking policy (see http://docs.doctrine-project.org/projects/doctrine-orm/en/stable/reference/change-tracking-policies.html)
## Deprecated `YAML` mapping drivers.
@@ -220,8 +852,8 @@ either:
- map those classes as `MappedSuperclass`
## Minor BC BREAK: ``EntityManagerInterface`` instead of ``EntityManager`` in type-hints
As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require
As of 2.5, classes requiring the ``EntityManager`` in any method signature will now require
an ``EntityManagerInterface`` instead.
If you are extending any of the following classes, then you need to check following
signatures:
@@ -314,7 +946,7 @@ the `Doctrine\ORM\Repository\DefaultRepositoryFactory`.
When executing DQL queries with new object expressions, instead of returning DTOs numerically indexes, it will now respect user provided aliases. Consider the following query:
SELECT new UserDTO(u.id,u.name) as user,new AddressDTO(a.street,a.postalCode) as address, a.id as addressId FROM User u INNER JOIN u.addresses a WITH a.isPrimary = true
Previously, your result would be similar to this:
array(

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env php
<?php
include('doctrine.php');
include(__DIR__ . '/doctrine.php');

View File

@@ -1,21 +1,14 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
fwrite(
STDERR,
'[Warning] The use of this script is discouraged. See'
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
. ' for instructions on bootstrapping the console runner.'
. PHP_EOL
);
echo PHP_EOL . PHP_EOL;
require_once 'Doctrine/Common/ClassLoader.php';

View File

@@ -1,25 +1,18 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
fwrite(
STDERR,
'[Warning] The use of this script is discouraged. See'
. ' https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/tools.html#doctrine-console'
. ' for instructions on bootstrapping the console runner.'
. PHP_EOL
);
echo PHP_EOL . PHP_EOL;
$autoloadFiles = [
__DIR__ . '/../vendor/autoload.php',
__DIR__ . '/../../../autoload.php'

View File

@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
convertDeprecationsToExceptions="true"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_driver" value="mysqli"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>

View File

@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
convertDeprecationsToExceptions="true"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_driver" value="pdo_mysql"/>
<var name="db_host" value="127.0.0.1" />
<var name="db_port" value="3306"/>

View File

@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
convertDeprecationsToExceptions="true"
>
<php>
<ini name="error_reporting" value="-1" />
<var name="db_driver" value="pdo_pgsql"/>
<var name="db_host" value="localhost" />
<var name="db_user" value="postgres" />

View File

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

View File

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

View File

@@ -1,12 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../vendor/phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="../../../vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
convertDeprecationsToExceptions="true"
>
<php>
<ini name="error_reporting" value="-1" />
<!-- use an in-memory sqlite database -->
<var name="db_driver" value="sqlite3"/>
<var name="db_memory" value="true"/>
<!-- necessary change for some CLI/console output test assertions -->
<env name="COLUMNS" value="120"/>
</php>

View File

@@ -13,32 +13,50 @@
{"name": "Marco Pivetta", "email": "ocramius@gmail.com"}
],
"config": {
"allow-plugins": {
"composer/package-versions-deprecated": true,
"dealerdirect/phpcodesniffer-composer-installer": true
},
"sort-packages": true
},
"require": {
"php": "^7.2|^8.0",
"ext-pdo": "*",
"composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.11.1",
"doctrine/cache": "^1.9.1",
"doctrine/collections": "^1.5",
"php": "^7.1 || ^8.0",
"composer-runtime-api": "^2",
"ext-ctype": "*",
"doctrine/cache": "^1.12.1 || ^2.1.1",
"doctrine/collections": "^1.5 || ^2.1",
"doctrine/common": "^3.0.3",
"doctrine/dbal": "^2.10.0",
"doctrine/event-manager": "^1.1",
"doctrine/inflector": "^1.4|^2.0",
"doctrine/instantiator": "^1.3",
"doctrine/lexer": "^1.0",
"doctrine/persistence": "^2.0",
"symfony/console": "^3.0|^4.0|^5.0"
"doctrine/dbal": "^2.13.1 || ^3.2",
"doctrine/deprecations": "^0.5.3 || ^1",
"doctrine/event-manager": "^1.2 || ^2",
"doctrine/inflector": "^1.4 || ^2.0",
"doctrine/instantiator": "^1.3 || ^2",
"doctrine/lexer": "^2",
"doctrine/persistence": "^2.4 || ^3",
"psr/cache": "^1 || ^2 || ^3",
"symfony/console": "^4.2 || ^5.0 || ^6.0",
"symfony/polyfill-php72": "^1.23",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"doctrine/coding-standard": "^8.0",
"phpstan/phpstan": "^0.12.18",
"phpunit/phpunit": "^8.5|^9.4",
"symfony/yaml": "^3.4|^4.0|^5.0",
"vimeo/psalm": "4.1.1"
"doctrine/annotations": "^1.13 || ^2",
"doctrine/coding-standard": "^9.0.2 || ^12.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "~1.4.10 || 1.10.28",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6",
"psr/log": "^1 || ^2 || ^3",
"squizlabs/php_codesniffer": "3.7.2",
"symfony/cache": "^4.4 || ^5.4 || ^6.0",
"symfony/var-exporter": "^4.4 || ^5.4 || ^6.2",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
"vimeo/psalm": "4.30.0 || 5.14.1"
},
"conflict": {
"doctrine/annotations": "<1.13 || >= 3.0"
},
"suggest": {
"ext-dom": "Provides support for XSD validation for XML mapping files",
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",
"symfony/yaml": "If you want to use YAML Metadata Mapping Driver"
},
"autoload": {
@@ -47,16 +65,12 @@
"autoload-dev": {
"psr-4": {
"Doctrine\\Tests\\": "tests/Doctrine/Tests",
"Doctrine\\StaticAnalysis\\": "tests/Doctrine/StaticAnalysis",
"Doctrine\\Performance\\": "tests/Doctrine/Performance"
}
},
"bin": ["bin/doctrine"],
"extra": {
"branch-alias": {
"dev-master": "2.7.x-dev"
}
},
"archive": {
"exclude": ["!vendor", "tests", "*phpunit.xml", ".travis.yml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
"exclude": ["!vendor", "tests", "*phpunit.xml", "build.xml", "build.properties", "composer.phar", "vendor/satooshi", "lib/vendor", "*.swp"]
}
}

View File

@@ -1,4 +1,4 @@
The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
The Doctrine ORM documentation is licensed under [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
Creative Commons Legal Code
@@ -359,5 +359,4 @@ Creative Commons Notice
available upon request from time to time. For the avoidance of doubt,
this trademark restriction does not form part of this License.
Creative Commons may be contacted at http://creativecommons.org/.
Creative Commons may be contacted at https://creativecommons.org/.

View File

@@ -1,201 +0,0 @@
# -*- coding: utf-8 -*-
#
# Doctrine 2 ORM documentation build configuration file, created by
# sphinx-quickstart on Fri Dec 3 18:10:24 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os, datetime
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath('_exts'))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['configurationblock']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Doctrine 2 ORM'
copyright = u'2010-%y, Doctrine Project Team'.format(datetime.date.today)
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2'
# The full version, including alpha/beta/rc tags.
release = '2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
language = 'en'
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
show_authors = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'doctrine'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ['_theme']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Doctrine2ORMdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Doctrine2ORM.tex', u'Doctrine 2 ORM Documentation',
u'Doctrine Project Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
primary_domain = "dcorm"
def linkcode_resolve(domain, info):
if domain == 'dcorm':
return 'http://'
return None

View File

@@ -4,7 +4,7 @@ Advanced field value conversion using custom mapping types
.. sectionauthor:: Jan Sorgalla <jsorgalla@googlemail.com>
When creating entities, you sometimes have the need to transform field values
before they are saved to the database. In Doctrine you can use Custom Mapping
before they are saved to the database. In Doctrine you can use Custom Mapping
Types to solve this (see: :ref:`reference-basic-mapping-custom-mapping-types`).
There are several ways to achieve this: converting the value inside the Type
@@ -15,7 +15,7 @@ type `Point <https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html>`_.
The ``Point`` type is part of the `Spatial extension <https://dev.mysql.com/doc/refman/8.0/en/spatial-extensions.html>`_
of MySQL and enables you to store a single location in a coordinate space by
using x and y coordinates. You can use the Point type to store a
using x and y coordinates. You can use the Point type to store a
longitude/latitude pair to represent a geographic location.
The entity
@@ -29,62 +29,42 @@ The entity class:
.. code-block:: php
<?php
namespace Geo\Entity;
/**
* @Entity
*/
use Geo\ValueObject\Point;
#[Entity]
class Location
{
/**
* @Column(type="point")
*
* @var \Geo\ValueObject\Point
*/
private $point;
#[Column(type: 'point')]
private Point $point;
/**
* @Column(type="string")
*
* @var string
*/
private $address;
#[Column]
private string $address;
/**
* @param \Geo\ValueObject\Point $point
*/
public function setPoint(\Geo\ValueObject\Point $point)
public function setPoint(Point $point): void
{
$this->point = $point;
}
/**
* @return \Geo\ValueObject\Point
*/
public function getPoint()
public function getPoint(): Point
{
return $this->point;
}
/**
* @param string $address
*/
public function setAddress($address)
public function setAddress(string $address): void
{
$this->address = $address;
}
/**
* @return string
*/
public function getAddress()
public function getAddress(): string
{
return $this->address;
}
}
We use the custom type ``point`` in the ``@Column`` docblock annotation of the
We use the custom type ``point`` in the ``#[Column]`` attribute of the
``$point`` field. We will create this custom mapping type in the next chapter.
The point class:
@@ -92,34 +72,23 @@ The point class:
.. code-block:: php
<?php
namespace Geo\ValueObject;
class Point
{
/**
* @param float $latitude
* @param float $longitude
*/
public function __construct($latitude, $longitude)
{
$this->latitude = $latitude;
$this->longitude = $longitude;
public function __construct(
private float $latitude,
private float $longitude,
) {
}
/**
* @return float
*/
public function getLatitude()
public function getLatitude(): float
{
return $this->latitude;
}
/**
* @return float
*/
public function getLongitude()
public function getLongitude(): float
{
return $this->longitude;
}
@@ -193,10 +162,10 @@ object into a string representation before saving to the database (in the
value from the database (in the ``convertToPHPValue`` method).
The format of the string representation format is called
`Well-known text (WKT) <http://en.wikipedia.org/wiki/Well-known_text>`_.
`Well-known text (WKT) <https://en.wikipedia.org/wiki/Well-known_text>`_.
The advantage of this format is, that it is both human readable and parsable by MySQL.
Internally, MySQL stores geometry values in a binary format that is not
Internally, MySQL stores geometry values in a binary format that is not
identical to the WKT format. So, we need to let MySQL transform the WKT
representation into its internal format.
@@ -210,13 +179,13 @@ which convert WKT strings to and from the internal format of MySQL.
.. note::
When using DQL queries, the ``convertToPHPValueSQL`` and
When using DQL queries, the ``convertToPHPValueSQL`` and
``convertToDatabaseValueSQL`` methods only apply to identification variables
and path expressions in SELECT clauses. Expressions in WHERE clauses are
and path expressions in SELECT clauses. Expressions in WHERE clauses are
**not** wrapped!
If you want to use Point values in WHERE clauses, you have to implement a
:doc:`user defined function <dql-user-defined-functions>` for
:doc:`user defined function <dql-user-defined-functions>` for
``PointFromText``.
Example usage
@@ -227,7 +196,7 @@ Example usage
<?php
// Bootstrapping stuff...
// $em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);
// $em = new \Doctrine\ORM\EntityManager($connection, $config);
// Setup custom mapping type
use Doctrine\DBAL\Types\Type;
@@ -252,5 +221,5 @@ Example usage
$query = $em->createQuery("SELECT l FROM Geo\Entity\Location l WHERE l.address = '1600 Amphitheatre Parkway, Mountain View, CA'");
$location = $query->getSingleResult();
/* @var Geo\ValueObject\Point */
/** @var Geo\ValueObject\Point */
$point = $location->getPoint();

View File

@@ -5,7 +5,7 @@ Persisting the Decorator Pattern
This recipe will show you a simple example of how you can use
Doctrine ORM to persist an implementation of the
`Decorator Pattern <http://en.wikipedia.org/wiki/Decorator_pattern>`_
`Decorator Pattern <https://en.wikipedia.org/wiki/Decorator_pattern>`_
Component
---------
@@ -23,48 +23,32 @@ concrete subclasses, ``ConcreteComponent`` and ``ConcreteDecorator``.
namespace Test;
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"cc" = "Test\Component\ConcreteComponent",
"cd" = "Test\Decorator\ConcreteDecorator"})
*/
#[Entity]
#[InheritanceType('SINGLE_TABLE')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['cc' => Component\ConcreteComponent::class,
'cd' => Decorator\ConcreteDecorator::class])]
abstract class Component
{
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;
#[Id, Column]
#[GeneratedValue(strategy: 'AUTO')]
protected int|null $id = null;
/** @Column(type="string", nullable=true) */
#[Column(type: 'string', nullable: true)]
protected $name;
/**
* Get id
* @return integer $id
*/
public function getId()
public function getId(): int|null
{
return $this->id;
}
/**
* Set name
* @param string $name
*/
public function setName($name)
public function setName(string $name): void
{
$this->name = $name;
}
/**
* Get name
* @return string $name
*/
public function getName()
public function getName(): string
{
return $this->name;
}
@@ -86,7 +70,7 @@ purpose of keeping this example simple).
use Test\Component;
/** @Entity */
#[Entity]
class ConcreteComponent extends Component
{}
@@ -103,14 +87,11 @@ use a ``MappedSuperclass`` for this.
namespace Test;
/** @MappedSuperclass */
#[MappedSuperclass]
abstract class Decorator extends Component
{
/**
* @OneToOne(targetEntity="Test\Component", cascade={"all"})
* @JoinColumn(name="decorates", referencedColumnName="id")
*/
#[OneToOne(targetEntity: Component::class, cascade: ['all'])]
#[JoinColumn(name: 'decorates', referencedColumnName: 'id')]
protected $decorates;
/**
@@ -126,25 +107,19 @@ use a ``MappedSuperclass`` for this.
* (non-PHPdoc)
* @see Test.Component::getName()
*/
public function getName()
public function getName(): string
{
return 'Decorated ' . $this->getDecorates()->getName();
}
/**
* the component being decorated
* @return Component
*/
protected function getDecorates()
/** the component being decorated */
protected function getDecorates(): Component
{
return $this->decorates;
}
/**
* sets the component being decorated
* @param Component $c
*/
protected function setDecorates(Component $c)
/** sets the component being decorated */
protected function setDecorates(Component $c): void
{
$this->decorates = $c;
}
@@ -187,27 +162,19 @@ of the getSpecial() method to its return value.
use Test\Decorator;
/** @Entity */
#[Entity]
class ConcreteDecorator extends Decorator
{
/** @Column(type="string", nullable=true) */
protected $special;
#[Column(type: 'string', nullable: true)]
protected string|null $special = null;
/**
* Set special
* @param string $special
*/
public function setSpecial($special)
public function setSpecial(string|null $special): void
{
$this->special = $special;
}
/**
* Get special
* @return string $special
*/
public function getSpecial()
public function getSpecial(): string|null
{
return $this->special;
}
@@ -216,7 +183,7 @@ of the getSpecial() method to its return value.
* (non-PHPdoc)
* @see Test.Component::getName()
*/
public function getName()
public function getName(): string
{
return '[' . $this->getSpecial()
. '] ' . parent::getName();
@@ -270,4 +237,3 @@ objects
echo $d->getName();
// prints: [Really] Decorated Test Component 2

View File

@@ -14,7 +14,7 @@ In Doctrine 1 the DQL language was not implemented using a real
parser. This made modifications of the DQL by the user impossible.
Doctrine ORM in contrast has a real parser for the DQL language,
which transforms the DQL statement into an
`Abstract Syntax Tree <http://en.wikipedia.org/wiki/Abstract_syntax_tree>`_
`Abstract Syntax Tree <https://en.wikipedia.org/wiki/Abstract_syntax_tree>`_
and generates the appropriate SQL statement for it. Since this
process is deterministic Doctrine heavily caches the SQL that is
generated from any given DQL query, which reduces the performance
@@ -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
@@ -88,7 +88,7 @@ API would look for this use-case:
$pageNum = 1;
$query = $em->createQuery($dql);
$query->setFirstResult( ($pageNum-1) * 20)->setMaxResults(20);
$totalResults = Paginate::count($query);
$results = $query->getResult();
@@ -101,12 +101,12 @@ The ``Paginate::count(Query $query)`` looks like:
{
static public function count(Query $query)
{
/* @var $countQuery Query */
/** @var Query $countQuery */
$countQuery = clone $query;
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, array('DoctrineExtensions\Paginate\CountSqlWalker'));
$countQuery->setFirstResult(null)->setMaxResults(null);
return $countQuery->getSingleScalarResult();
}
}
@@ -137,13 +137,13 @@ implementation is:
break;
}
}
$pathExpression = new PathExpression(
PathExpression::TYPE_STATE_FIELD | PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION, $parentName,
$parent['metadata']->getSingleIdentifierFieldName()
);
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
$AST->selectClause->selectExpressions = array(
new SelectExpression(
new AggregateExpression('count', $pathExpression, true), null
@@ -196,7 +196,7 @@ modify the generation of the SELECT clause, adding the
public function walkSelectClause($selectClause)
{
$sql = parent::walkSelectClause($selectClause);
if ($this->getQuery()->getHint('mysqlWalker.sqlNoCache') === true) {
if ($selectClause->isDistinct) {
$sql = str_replace('SELECT DISTINCT', 'SELECT DISTINCT SQL_NO_CACHE', $sql);
@@ -204,7 +204,7 @@ modify the generation of the SELECT clause, adding the
$sql = str_replace('SELECT', 'SELECT SQL_NO_CACHE', $sql);
}
}
return $sql;
}
}

View File

@@ -45,8 +45,8 @@ configuration:
$config->addCustomStringFunction($name, $class);
$config->addCustomNumericFunction($name, $class);
$config->addCustomDatetimeFunction($name, $class);
$em = EntityManager::create($dbParams, $config);
$em = new EntityManager($connection, $config);
The ``$name`` is the name the function will be referred to in the
DQL query. ``$class`` is a string of a class-name which has to
@@ -96,7 +96,7 @@ discuss it step by step:
// (1)
public $firstDateExpression = null;
public $secondDateExpression = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER); // (2)
@@ -106,7 +106,7 @@ discuss it step by step:
$this->secondDateExpression = $parser->ArithmeticPrimary(); // (6)
$parser->match(Lexer::T_CLOSE_PARENTHESIS); // (3)
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DATEDIFF(' .
@@ -131,8 +131,8 @@ generation of a DateDiff FunctionNode somewhere in the AST of the
dql statement.
The ``ArithmeticPrimary`` method call is the most common
denominator of valid EBNF tokens taken from the
`DQL EBNF grammar <http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#ebnf>`_
denominator of valid EBNF tokens taken from the :ref:`DQL EBNF grammar
<dql_ebnf_grammar>`
that matches our requirements for valid input into the DateDiff Dql
function. Picking the right tokens for your methods is a tricky
business, but the EBNF grammar is pretty helpful finding it, as is
@@ -180,28 +180,28 @@ I'll skip the blah and show the code for this function:
public $firstDateExpression = null;
public $intervalExpression = null;
public $unit = null;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->firstDateExpression = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_COMMA);
$parser->match(Lexer::T_IDENTIFIER);
$this->intervalExpression = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_IDENTIFIER);
/* @var $lexer Lexer */
/** @var Lexer $lexer */
$lexer = $parser->getLexer();
$this->unit = $lexer->token['value'];
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'DATE_ADD(' .
@@ -246,6 +246,4 @@ vendor sql functions and extend the DQL languages scope.
Code for this Extension to DQL and other Doctrine Extensions can be
found
`in the GitHub DoctrineExtensions repository <http://github.com/beberlei/DoctrineExtensions>`_.
`in the GitHub DoctrineExtensions repository <https://github.com/beberlei/DoctrineExtensions>`_.

View File

@@ -3,42 +3,69 @@ Entities in the Session
There are several use-cases to save entities in the session, for example:
1. User object
1. User data
2. Multi-step forms
To achieve this with Doctrine you have to pay attention to some details to get
this working.
Merging entity into an EntityManager
------------------------------------
Updating an entity
------------------
In Doctrine an entity objects has to be "managed" by an EntityManager to be
updateable. Entities saved into the session are not managed in the next request
anymore. This means that you have to register these entities with an
EntityManager again if you want to change them or use them as part of
references between other entities. You can achieve this by calling
``EntityManager#merge()``.
updatable. Entities saved into the session are not managed in the next request
anymore. This means that you have to update the entities with the stored session
data after you fetch the entities from the EntityManager again.
For a representative User object the code to get turn an instance from
the session into a managed Doctrine object looks like this:
For a representative User object the code to get data from the session into a
managed Doctrine object can look like these examples:
Working with scalars
~~~~~~~~~~~~~~~~~~~~
In simpler applications there is no need to work with objects in sessions and you can use
separate session elements.
.. code-block:: php
<?php
require_once 'bootstrap.php';
$em = GetEntityManager(); // creates an EntityManager
session_start();
if (isset($_SESSION['user']) && $_SESSION['user'] instanceof User) {
$user = $_SESSION['user'];
$user = $em->merge($user);
if (isset($_SESSION['userId']) && is_int($_SESSION['userId'])) {
$userId = $_SESSION['userId'];
$em = GetEntityManager(); // creates an EntityManager
$user = $em->find(User::class, $userId);
$user->setValue($_SESSION['storedValue']);
$em->flush();
}
.. note::
Working with custom data transfer objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A frequent mistake is not to get the merged user object from the return
value of ``EntityManager#merge()``. The entity object passed to merge is
not necessarily the same object that is returned from the method.
If objects are needed, we discourage the storage of entity objects in the session. It's
preferable to use a `DTO (data transfer object) <https://en.wikipedia.org/wiki/Data_transfer_object>`_
instead and merge the DTO data later with the entity.
.. code-block:: php
<?php
require_once 'bootstrap.php';
session_start();
if (isset($_SESSION['user']) && $_SESSION['user'] instanceof UserDto) {
$userDto = $_SESSION['user'];
$em = GetEntityManager(); // creates an EntityManager
$userEntity = $em->find(User::class, $userDto->getId());
$userEntity->populateFromDto($userDto);
$em->flush();
}
Serializing entity into the session
-----------------------------------
@@ -47,22 +74,20 @@ Entities that are serialized into the session normally contain references to
other entities as well. Think of the user entity has a reference to their
articles, groups, photos or many other different entities. If you serialize
this object into the session then you don't want to serialize the related
entities as well. This is why you should call ``EntityManager#detach()`` on this
object or implement the __sleep() magic method on your entity.
entities as well. This is why you shouldn't serialize an entity and use
only the needed values of it. This can happen with the help of a DTO.
.. code-block:: php
<?php
require_once 'bootstrap.php';
$em = GetEntityManager(); // creates an EntityManager
$user = $em->find("User", 1);
$em->detach($user);
$_SESSION['user'] = $user;
$userDto = new UserDto($user->getId(), $user->getFirstName(), $user->getLastName());
// or "UserDto::createFrom($user);", but don't store an entity in a property. Only its values without relations.
.. note::
$_SESSION['user'] = $userDto;
When you called detach on your objects they get "unmanaged" with that
entity manager. This means you cannot use them as part of write operations
during ``EntityManager#flush()`` anymore in this request.

View File

@@ -6,7 +6,7 @@ Implementing ArrayAccess for Domain Objects
This recipe will show you how to implement ArrayAccess for your
domain objects in order to allow more uniform access, for example
in templates. In these examples we will implement ArrayAccess on a
`Layer Supertype <http://martinfowler.com/eaaCatalog/layerSupertype.html>`_
`Layer Supertype <https://martinfowler.com/eaaCatalog/layerSupertype.html>`_
for all our domain objects.
Option 1

View File

@@ -7,9 +7,14 @@ The NOTIFY change-tracking policy is the most effective
change-tracking policy provided by Doctrine but it requires some
boilerplate code. This recipe will show you how this boilerplate
code should look like. We will implement it on a
`Layer Supertype <http://martinfowler.com/eaaCatalog/layerSupertype.html>`_
`Layer Supertype <https://martinfowler.com/eaaCatalog/layerSupertype.html>`_
for all our domain objects.
.. note::
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
Implementing NotifyPropertyChanged
----------------------------------
@@ -24,15 +29,15 @@ implement the ``NotifyPropertyChanged`` interface from the
<?php
use Doctrine\Persistence\NotifyPropertyChanged;
use Doctrine\Persistence\PropertyChangedListener;
abstract class DomainObject implements NotifyPropertyChanged
{
private $listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener) {
$this->listeners[] = $listener;
}
/** Notifies listeners of a change. */
protected function onPropertyChanged($propName, $oldValue, $newValue) {
if ($this->listeners) {
@@ -50,12 +55,12 @@ listeners:
.. code-block:: php
<?php
// Mapping not shown, either in annotations, xml or yaml as usual
// Mapping not shown, either in attributes, annotations, xml or yaml as usual
class MyEntity extends DomainObject
{
private $data;
// ... other fields as usual
public function setData($data) {
if ($data != $this->data) { // check: is it actually modified?
$this->onPropertyChanged('data', $this->data, $data);
@@ -68,5 +73,3 @@ The check whether the new value is different from the old one is
not mandatory but recommended. That way you can avoid unnecessary
updates and also have full control over when you consider a
property changed.

View File

@@ -1,78 +0,0 @@
Implementing Wakeup or Clone
============================
.. sectionauthor:: Roman Borschel (roman@code-factory.org)
As explained in the
`restrictions for entity classes in the manual <http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/architecture.html#entities>`_,
it is usually not allowed for an entity to implement ``__wakeup``
or ``__clone``, because Doctrine makes special use of them.
However, it is quite easy to make use of these methods in a safe
way by guarding the custom wakeup or clone code with an entity
identity check, as demonstrated in the following sections.
Safely implementing __wakeup
----------------------------
To safely implement ``__wakeup``, simply enclose your
implementation code in an identity check as follows:
.. code-block:: php
<?php
class MyEntity
{
private $id; // This is the identifier of the entity.
//...
public function __wakeup()
{
// If the entity has an identity, proceed as normal.
if ($this->id) {
// ... Your code here as normal ...
}
// otherwise do nothing, do NOT throw an exception!
}
//...
}
Safely implementing __clone
---------------------------
Safely implementing ``__clone`` is pretty much the same:
.. code-block:: php
<?php
class MyEntity
{
private $id; // This is the identifier of the entity.
//...
public function __clone()
{
// If the entity has an identity, proceed as normal.
if ($this->id) {
// ... Your code here as normal ...
}
// otherwise do nothing, do NOT throw an exception!
}
//...
}
Summary
-------
As you have seen, it is quite easy to safely make use of
``__wakeup`` and ``__clone`` in your entities without adding any
really Doctrine-specific or Doctrine-dependant code.
These implementations are possible and safe because when Doctrine
invokes these methods, the entities never have an identity (yet).
Furthermore, it is possibly a good idea to check for the identity
in your code anyway, since it's rarely the case that you want to
unserialize or clone an entity with no identity.

View File

@@ -127,7 +127,8 @@ the targetEntity resolution will occur reliably:
// Add the ResolveTargetEntityListener
$evm->addEventListener(Doctrine\ORM\Events::loadClassMetadata, $rtel);
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm);
$connection = \Doctrine\DBAL\DriverManager::createConnection($connectionOptions, $config, $evm);
$em = new \Doctrine\ORM\EntityManager($connection, $config, $evm);
Final Thoughts
--------------
@@ -136,5 +137,3 @@ With the ``ResolveTargetEntityListener``, we are able to decouple our
bundles, keeping them usable by themselves, but still being able to
define relationships between different objects. By using this method,
I've found my bundles end up being easier to maintain independently.

View File

@@ -47,7 +47,7 @@ appropriate autoloaders.
}
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide']) {
if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_MANY && $mapping['isOwningSide']) {
$mappedTableName = $mapping['joinTable']['name'];
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
}
@@ -81,6 +81,4 @@ before the prefix has been set.
$tablePrefix = new \DoctrineExtensions\TablePrefix('prefix_');
$evm->addEventListener(\Doctrine\ORM\Events::loadClassMetadata, $tablePrefix);
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config, $evm);
$em = new \Doctrine\ORM\EntityManager($connection, $config, $evm);

View File

@@ -87,12 +87,12 @@ Such an interface could look like this:
* @return \Zend_View_Helper_Interface
*/
public function setView(\Zend_View_Interface $view);
/**
* @return \Zend_View_Interface
*/
public function getView();
/**
* Renders this strategy. This method will be called when the user
* displays the site.
@@ -100,7 +100,7 @@ Such an interface could look like this:
* @return string
*/
public function renderFrontend();
/**
* Renders the backend of this block. This method will be called when
* a user tries to reconfigure this block instance.
@@ -118,21 +118,21 @@ Such an interface could look like this:
* @return array
*/
public function getRequiredPanelTypes();
/**
* Determines whether a Block is able to use a given type or not
* @param string $typeName The typename
* @return boolean
*/
public function canUsePanelType($typeName);
public function setBlockEntity(AbstractBlock $block);
public function getBlockEntity();
}
As you can see, we have a method "setBlockEntity" which ties a potential strategy to an object of type AbstractBlock. This type will simply define the basic behaviour of our blocks and could potentially look something like this:
.. code-block:: php
<?php
@@ -154,8 +154,8 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
* This var contains the classname of the strategy
* that is used for this blockitem. (This string (!) value will be persisted by Doctrine ORM)
*
* This is a doctrine field, so make sure that you use an @column annotation or setup your
* yaml or xml files correctly
* This is a doctrine field, so make sure that you use a
#[Column] attribute or setup your yaml or xml files correctly
* @var string
*/
protected $strategyClassName;
@@ -177,7 +177,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
public function getStrategyClassName() {
return $this->strategyClassName;
}
/**
* Returns the instantiated strategy
*
@@ -186,7 +186,7 @@ As you can see, we have a method "setBlockEntity" which ties a potential strateg
public function getStrategyInstance() {
return $this->strategyInstance;
}
/**
* Sets the strategy this block / panel should work as. Make sure that you've used
* this method before persisting the block!
@@ -213,28 +213,29 @@ This might look like this:
.. code-block:: php
<?php
use \Doctrine\ORM,
\Doctrine\Common;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
/**
* The BlockStrategyEventListener will initialize a strategy after the
* block itself was loaded.
*/
class BlockStrategyEventListener implements Common\EventSubscriber {
class BlockStrategyEventListener implements EventSubscriber {
protected $view;
public function __construct(\Zend_View_Interface $view) {
$this->view = $view;
}
public function getSubscribedEvents() {
return array(ORM\Events::postLoad);
return array(Events::postLoad);
}
public function postLoad(ORM\Event\LifecycleEventArgs $args) {
$blockItem = $args->getEntity();
public function postLoad(LifecycleEventArgs $args) {
$blockItem = $args->getObject();
// Both blocks and panels are instances of Block\AbstractBlock
if ($blockItem instanceof Block\AbstractBlock) {
$strategy = $blockItem->getStrategyClassName();
@@ -250,5 +251,3 @@ This might look like this:
In this example, even some variables are set - like a view object
or a specific configuration object.

View File

@@ -36,12 +36,12 @@ are allowed to:
public function assertCustomerAllowedBuying()
{
$orderLimit = $this->customer->getOrderLimit();
$amount = 0;
foreach ($this->orderLines as $line) {
$amount += $line->getAmount();
}
if ($amount > $orderLimit) {
throw new CustomerOrderLimitExceededException();
}
@@ -53,7 +53,25 @@ code, enforcing it at any time is important so that customers with
a unknown reputation don't owe your business too much money.
We can enforce this constraint in any of the metadata drivers.
First Annotations:
First Attributes:
.. code-block:: php
<?php
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
use Doctrine\ORM\Mapping\PrePersist;
use Doctrine\ORM\Mapping\PreUpdate;
#[Entity]
#[HasLifecycleCallbacks]
class Order
{
#[PrePersist, PreUpdate]
public function assertCustomerAllowedBuying() {}
}
As Annotations:
.. code-block:: php
@@ -83,9 +101,6 @@ In XML Mappings:
</entity>
</doctrine-mapping>
YAML needs some little change yet, to allow multiple lifecycle
events for one method, this will happen before Beta 1 though.
Now validation is performed whenever you call
``EntityManager#persist($order)`` or when you call
``EntityManager#flush()`` and an order is about to be updated. Any
@@ -101,19 +116,17 @@ validation callbacks.
<?php
class Order
{
/**
* @PrePersist @PreUpdate
*/
#[PrePersist, PreUpdate]
public function validate()
{
if (!($this->plannedShipDate instanceof DateTime)) {
throw new ValidateException();
}
if ($this->plannedShipDate->format('U') < time()) {
throw new ValidateException();
}
if ($this->customer == null) {
throw new OrderRequiresCustomerException();
}

View File

@@ -15,13 +15,16 @@ these comparisons are always made **BY REFERENCE**. That means the following cha
.. code-block:: php
<?php
/** @Entity */
use DateTime;
#[Entity]
class Article
{
/** @Column(type="datetime") */
private $updated;
#[Column(type: 'datetime')]
private DateTime $updated;
public function setUpdated()
public function setUpdated(): void
{
// will NOT be saved in the database
$this->updated->modify("now");
@@ -33,12 +36,14 @@ The way to go would be:
.. code-block:: php
<?php
use DateTime;
class Article
{
public function setUpdated()
public function setUpdated(): void
{
// WILL be saved in the database
$this->updated = new \DateTime("now");
$this->updated = new DateTime("now");
}
}
@@ -61,7 +66,7 @@ to manage this mess,
however let me crush your expectations fast. There is not a single database out there (supported by Doctrine ORM)
that supports timezones correctly. Correctly here means that you can cover all the use-cases that
can come up with timezones. If you don't believe me you should read up on `Storing DateTime
in Databases <http://derickrethans.nl/storing-date-time-in-database.html>`_.
in Databases <https://derickrethans.nl/storing-date-time-in-database.html>`_.
The problem is simple. Not a single database vendor saves the timezone, only the differences to UTC.
However with frequent daylight saving and political timezone changes you can have a UTC offset that moves
@@ -84,16 +89,14 @@ the UTC time at the time of the booking and the timezone the event happened in.
namespace DoctrineExtensions\DBAL\Types;
use DateTimeZone;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\DateTimeType;
class UTCDateTimeType extends DateTimeType
{
/**
* @var \DateTimeZone
*/
private static $utc;
private static DateTimeZone $utc;
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
@@ -126,10 +129,10 @@ the UTC time at the time of the booking and the timezone the event happened in.
return $converted;
}
private static function getUtc(): \DateTimeZone
private static function getUtc(): DateTimeZone
{
return self::$utc ?: self::$utc = new \DateTimeZone('UTC');
return self::$utc ??= new DateTimeZone('UTC');
}
}

View File

@@ -16,11 +16,10 @@ 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
of contents <toc>`.
If you need more structure over the different topics you can browse the table
of contents.
Getting Started
---------------
@@ -35,31 +34,32 @@ Mapping Objects onto a Database
-------------------------------
* **Mapping**:
:doc:`Objects <reference/basic-mapping>` |
:doc:`Associations <reference/association-mapping>` |
:doc:`Objects <reference/basic-mapping>` \|
:doc:`Associations <reference/association-mapping>` \|
:doc:`Inheritance <reference/inheritance-mapping>`
* **Drivers**:
:doc:`Docblock Annotations <reference/annotations-reference>` |
:doc:`XML <reference/xml-mapping>` |
:doc:`YAML <reference/yaml-mapping>` |
:doc:`Docblock Annotations <reference/annotations-reference>` \|
:doc:`Attributes <reference/attributes-reference>` \|
:doc:`XML <reference/xml-mapping>` \|
:doc:`YAML <reference/yaml-mapping>` \|
:doc:`PHP <reference/php-mapping>`
Working with Objects
--------------------
* **Basic Reference**:
:doc:`Entities <reference/working-with-objects>` |
:doc:`Associations <reference/working-with-associations>` |
:doc:`Entities <reference/working-with-objects>` \|
:doc:`Associations <reference/working-with-associations>` \|
:doc:`Events <reference/events>`
* **Query Reference**:
:doc:`DQL <reference/dql-doctrine-query-language>` |
:doc:`QueryBuilder <reference/query-builder>` |
:doc:`DQL <reference/dql-doctrine-query-language>` \|
:doc:`QueryBuilder <reference/query-builder>` \|
:doc:`Native SQL <reference/native-sql>`
* **Internals**:
:doc:`Internals explained <reference/unitofwork>` |
:doc:`Internals explained <reference/unitofwork>` \|
:doc:`Associations <reference/unitofwork-associations>`
Advanced Topics
@@ -72,6 +72,7 @@ Advanced Topics
* :doc:`Transactions and Concurrency <reference/transactions-and-concurrency>`
* :doc:`Filters <reference/filters>`
* :doc:`NamingStrategy <reference/namingstrategy>`
* :doc:`TypedFieldMapper <reference/typedfieldmapper>`
* :doc:`Improving Performance <reference/improving-performance>`
* :doc:`Caching <reference/caching>`
* :doc:`Partial Objects <reference/partial-objects>`
@@ -101,21 +102,20 @@ Cookbook
--------
* **Patterns**:
:doc:`Aggregate Fields <cookbook/aggregate-fields>` |
:doc:`Decorator Pattern <cookbook/decorator-pattern>` |
:doc:`Aggregate Fields <cookbook/aggregate-fields>` \|
:doc:`Decorator Pattern <cookbook/decorator-pattern>` \|
:doc:`Strategy Pattern <cookbook/strategy-cookbook-introduction>`
* **DQL Extension Points**:
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` |
:doc:`DQL Custom Walkers <cookbook/dql-custom-walkers>` \|
:doc:`DQL User-Defined-Functions <cookbook/dql-user-defined-functions>`
* **Implementation**:
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` |
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` |
:doc:`Using Wakeup Or Clone <cookbook/implementing-wakeup-or-clone>` |
:doc:`Working with DateTime <cookbook/working-with-datetime>` |
:doc:`Validation <cookbook/validation-of-entities>` |
:doc:`Entities in the Session <cookbook/entities-in-session>` |
:doc:`Array Access <cookbook/implementing-arrayaccess-for-domain-objects>` \|
:doc:`Notify ChangeTracking Example <cookbook/implementing-the-notify-changetracking-policy>` \|
:doc:`Working with DateTime <cookbook/working-with-datetime>` \|
:doc:`Validation <cookbook/validation-of-entities>` \|
:doc:`Entities in the Session <cookbook/entities-in-session>` \|
:doc:`Keeping your Modules independent <cookbook/resolve-target-entity-listener>`
* **Hidden Gems**
@@ -124,5 +124,3 @@ Cookbook
* **Custom Datatypes**
:doc:`MySQL Enums <cookbook/mysql-enums>`
:doc:`Advanced Field Value Conversion <cookbook/advanced-field-value-conversion-using-custom-mapping-types>`
.. include:: toc.rst

View File

@@ -9,22 +9,29 @@ steps of configuration.
.. code-block:: php
<?php
use Doctrine\ORM\EntityManager,
Doctrine\ORM\Configuration;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
use Doctrine\ORM\ORMSetup;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
// ...
if ($applicationMode == "development") {
$cache = new \Doctrine\Common\Cache\ArrayCache;
$queryCache = new ArrayAdapter();
$metadataCache = new ArrayAdapter();
} else {
$cache = new \Doctrine\Common\Cache\ApcCache;
$queryCache = new PhpFilesAdapter('doctrine_queries');
$metadataCache = new PhpFilesAdapter('doctrine_metadata');
}
$config = new Configuration;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
$config->setMetadataCache($metadataCache);
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);
$config->setQueryCache($queryCache);
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');
@@ -34,26 +41,29 @@ steps of configuration.
$config->setAutoGenerateProxyClasses(false);
}
$connectionOptions = array(
$connection = DriverManager::getConnection([
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
'path' => 'database.sqlite',
], $config);
$em = EntityManager::create($connectionOptions, $config);
$em = new EntityManager($connection, $config);
Doctrine and Caching
--------------------
Doctrine is optimized for working with caches. The main parts in Doctrine
that are optimized for caching are the metadata mapping information with
the metadata cache and the DQL to SQL conversions with the query cache.
These 2 caches require only an absolute minimum of memory yet they heavily
improve the runtime performance of Doctrine.
Doctrine does not bundle its own cache implementation anymore. Instead,
the PSR-6 standard interfaces are used to access the cache. In the examples
in this documentation, Symfony Cache is used as a reference implementation.
.. note::
Do not use Doctrine without a metadata and query cache!
Doctrine is optimized for working with caches. The main
parts in Doctrine that are optimized for caching are the metadata
mapping information with the metadata cache and the DQL to SQL
conversions with the query cache. These 2 caches require only an
absolute minimum of memory yet they heavily improve the runtime
performance of Doctrine. The recommended cache driver to use with
Doctrine is `APC <http://www.php.net/apc>`_. APC provides you with
an opcode-cache (which is highly recommended anyway) and a very
fast in-memory cache storage that you can use for the metadata and
query caches as seen in the previous code snippet.
Configuration Options
---------------------
@@ -101,29 +111,33 @@ Gets or sets the metadata driver implementation that is used by
Doctrine to acquire the object-relational metadata for your
classes.
There are currently 4 available implementations:
There are currently 5 available implementations:
- ``Doctrine\ORM\Mapping\Driver\AnnotationDriver``
- ``Doctrine\ORM\Mapping\Driver\AttributeDriver``
- ``Doctrine\ORM\Mapping\Driver\XmlDriver``
- ``Doctrine\ORM\Mapping\Driver\YamlDriver``
- ``Doctrine\ORM\Mapping\Driver\DriverChain``
- ``Doctrine\ORM\Mapping\Driver\AnnotationDriver`` (deprecated and will
be removed in ``doctrine/orm`` 3.0)
- ``Doctrine\ORM\Mapping\Driver\YamlDriver`` (deprecated and will be
removed in ``doctrine/orm`` 3.0)
Throughout the most part of this manual the AnnotationDriver is
used in the examples. For information on the usage of the XmlDriver
or YamlDriver please refer to the dedicated chapters
``XML Mapping`` and ``YAML Mapping``.
Throughout the most part of this manual the AttributeDriver is
used in the examples. For information on the usage of the
AnnotationDriver, XmlDriver or YamlDriver please refer to the dedicated
chapters ``Annotation Reference``, ``XML Mapping`` and ``YAML Mapping``.
The annotation driver can be configured with a factory method on
the ``Doctrine\ORM\Configuration``:
The attribute driver can be injected in the ``Doctrine\ORM\Configuration``:
.. code-block:: php
<?php
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
$driverImpl = new AttributeDriver(['/path/to/lib/MyProject/Entities'], true);
$config->setMetadataDriverImpl($driverImpl);
The path information to the entities is required for the annotation
The path information to the entities is required for the attribute
driver, because otherwise mass-operations on all entities through
the console could not work correctly. All of metadata drivers
accept either a single directory as a string or an array of
@@ -136,30 +150,21 @@ Metadata Cache (***RECOMMENDED***)
.. code-block:: php
<?php
$config->setMetadataCacheImpl($cache);
$config->getMetadataCacheImpl();
$config->setMetadataCache($cache);
$config->getMetadataCache();
Gets or sets the cache implementation to use for caching metadata
information, that is, all the information you supply via
Gets or sets the cache adapter to use for caching metadata
information, that is, all the information you supply via attributes,
annotations, xml or yaml, so that they do not need to be parsed and
loaded from scratch on every single request which is a waste of
resources. The cache implementation must implement the
``Doctrine\Common\Cache\Cache`` interface.
resources. The cache implementation must implement the PSR-6
``Psr\Cache\CacheItemPoolInterface`` interface.
Usage of a metadata cache is highly recommended.
The recommended implementations for production are:
- ``Doctrine\Common\Cache\ApcCache``
- ``Doctrine\Common\Cache\ApcuCache``
- ``Doctrine\Common\Cache\MemcacheCache``
- ``Doctrine\Common\Cache\XcacheCache``
- ``Doctrine\Common\Cache\RedisCache``
For development you should use the
``Doctrine\Common\Cache\ArrayCache`` which only caches data on a
per-request basis.
For development you should use an array cache like
``Symfony\Component\Cache\Adapter\ArrayAdapter``
which only caches data on a per-request basis.
Query Cache (***RECOMMENDED***)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -167,8 +172,8 @@ Query Cache (***RECOMMENDED***)
.. code-block:: php
<?php
$config->setQueryCacheImpl($cache);
$config->getQueryCacheImpl();
$config->setQueryCache($cache);
$config->getQueryCache();
Gets or sets the cache implementation to use for caching DQL
queries, that is, the result of a DQL parsing process that includes
@@ -180,18 +185,9 @@ minimal memory usage in your cache).
Usage of a query cache is highly recommended.
The recommended implementations for production are:
- ``Doctrine\Common\Cache\ApcCache``
- ``Doctrine\Common\Cache\ApcuCache``
- ``Doctrine\Common\Cache\MemcacheCache``
- ``Doctrine\Common\Cache\XcacheCache``
- ``Doctrine\Common\Cache\RedisCache``
For development you should use the
``Doctrine\Common\Cache\ArrayCache`` which only caches data on a
per-request basis.
For development you should use an array cache like
``Symfony\Component\Cache\Adapter\ArrayAdapter``
which only caches data on a per-request basis.
SQL Logger (***Optional***)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -204,10 +200,7 @@ SQL Logger (***Optional***)
Gets or sets the logger to use for logging all SQL statements
executed by Doctrine. The logger class must implement the
``Doctrine\DBAL\Logging\SQLLogger`` interface. A simple default
implementation that logs to the standard output using ``echo`` and
``var_dump`` can be found at
``Doctrine\DBAL\Logging\EchoSQLLogger``.
deprecated ``Doctrine\DBAL\Logging\SQLLogger`` interface.
Auto-generating Proxy Classes (***OPTIONAL***)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -223,7 +216,7 @@ option that controls this behavior is:
Possible values for ``$mode`` are:
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_NEVER``
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_NEVER``
Never autogenerate a proxy. You will need to generate the proxies
manually, for this use the Doctrine Console like so:
@@ -239,17 +232,17 @@ methods were added to the entity class that are not yet in the proxy class.
In such a case, simply use the Doctrine Console to (re)generate the
proxy classes.
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_ALWAYS``
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_ALWAYS``
Always generates a new proxy in every request and writes it to disk.
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS``
Generate the proxy class when the proxy file does not exist.
This strategy causes a file exists call whenever any proxy is
used the first time in a request.
- ``Doctrine\Common\Proxy\AbstractProxyFactory::AUTOGENERATE_EVAL``
- ``Doctrine\ORM\Proxy\ProxyFactory::AUTOGENERATE_EVAL``
Generate the proxy classes and evaluate them on the fly via eval(),
avoiding writing the proxies to disk.
@@ -268,10 +261,10 @@ Development vs Production Configuration
You should code your Doctrine2 bootstrapping with two different
runtime models in mind. There are some serious benefits of using
APC or Memcache in production. In development however this will
APCu or Memcache in production. In development however this will
frequently give you fatal errors, when you change your entities and
the cache still keeps the outdated metadata. That is why we
recommend the ``ArrayCache`` for development.
recommend an array cache for development.
Furthermore you should have the Auto-generating Proxy Classes
option to true in development and to false in production. If this
@@ -283,15 +276,13 @@ proxy sets an exclusive file lock which can cause serious
performance bottlenecks in systems with regular concurrent
requests.
Connection Options
------------------
Connection
----------
The ``$connectionOptions`` passed as the first argument to
``EntityManager::create()`` has to be either an array or an
instance of ``Doctrine\DBAL\Connection``. If an array is passed it
is directly passed along to the DBAL Factory
``Doctrine\DBAL\DriverManager::getConnection()``. The DBAL
configuration is explained in the
The ``$connection`` passed as the first argument to he constructor of
``EntityManager`` has to be an instance of ``Doctrine\DBAL\Connection``.
You can use the factory ``Doctrine\DBAL\DriverManager::getConnection()``
to create such a connection. The DBAL configuration is explained in the
`DBAL section <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/configuration.html>`_.
Proxy Objects
@@ -320,10 +311,12 @@ Reference Proxies
The method ``EntityManager#getReference($entityName, $identifier)``
lets you obtain a reference to an entity for which the identifier
is known, without loading that entity from the database. This is
useful, for example, as a performance enhancement, when you want to
establish an association to an entity for which you have the
identifier. You could simply do this:
is known, without necessarily loading that entity from the database.
This is useful, for example, as a performance enhancement, when you
want to establish an association to an entity for which you have the
identifier.
Consider the following example:
.. code-block:: php
@@ -333,14 +326,33 @@ identifier. You could simply do this:
$item = $em->getReference('MyProject\Model\Item', $itemId);
$cart->addItem($item);
Here, we added an Item to a Cart without loading the Item from the
database. If you invoke any method on the Item instance, it would
fully initialize its state transparently from the database. Here
$item is actually an instance of the proxy class that was generated
for the Item class but your code does not need to care. In fact it
**should not care**. Proxy objects should be transparent to your
Whether the object being returned from ``EntityManager#getReference()``
is a proxy or a direct instance of the entity class may depend on different
factors, including whether the entity has already been loaded into memory
or entity inheritance being used. But your code does not need to care
and in fact it **should not care**. Proxy objects should be transparent to your
code.
When using the ``EntityManager#getReference()`` method, you need to be aware
of a few peculiarities.
At the best case, the ORM can avoid querying the database at all. But, that
also means that this method will not throw an exception when an invalid value
for the ``$identifier`` parameter is passed. ``$identifier`` values are
not checked and there is no guarantee that the requested entity instance even
exists the method will still return a proxy object.
Its only when the proxy has to be fully initialized or associations cannot
be written to the database that invalid ``$identifier`` values may lead to
exceptions.
The ``EntityManager#getReference()`` is mostly useful when you only
need a reference to some entity to make an association, like in the example
above. In that case, it can save you from loading data from the database
that you don't need. But remember as soon as you read any property values
besides those making up the ID, a database request will be made to initialize
all fields.
Association proxies
~~~~~~~~~~~~~~~~~~~
@@ -413,15 +425,15 @@ Multiple Metadata Sources
When using different components using Doctrine ORM you may end up
with them using two different metadata drivers, for example XML and
YAML. You can use the DriverChain Metadata implementations to
YAML. You can use the MappingDriverChain Metadata implementations to
aggregate these drivers based on namespaces:
.. code-block:: php
<?php
use Doctrine\ORM\Mapping\Driver\DriverChain;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;
$chain = new DriverChain();
$chain = new MappingDriverChain();
$chain->addDriver($xmlDriver, 'Doctrine\Tests\Models\Company');
$chain->addDriver($yamlDriver, 'Doctrine\Tests\ORM\Mapping');
@@ -449,22 +461,22 @@ That will be available for all entities without a custom repository class.
The default value is ``Doctrine\ORM\EntityRepository``.
Any repository class must be a subclass of EntityRepository otherwise you got an ORMException
Setting up the Console
----------------------
Ignoring entities (***OPTIONAL***)
-----------------------------------
Doctrine uses the Symfony Console component for generating the command
line interface. You can take a look at the ``vendor/bin/doctrine.php``
script and the ``Doctrine\ORM\Tools\Console\ConsoleRunner`` command
for inspiration how to setup the cli.
In general the required code looks like this:
Specifies the Entity FQCNs to ignore.
SchemaTool will then skip these (e.g. when comparing schemas).
.. code-block:: php
<?php
$cli = new Application('Doctrine Command Line Interface', \Doctrine\ORM\Version::VERSION);
$cli->setCatchExceptions(true);
$cli->setHelperSet($helperSet);
Doctrine\ORM\Tools\Console\ConsoleRunner::addCommands($cli);
$cli->run();
$config->setSchemaIgnoreClasses([$fqcn]);
$config->getSchemaIgnoreClasses();
Setting up the Console
----------------------
Doctrine uses the Symfony Console component for generating the command
line interface. You can take a look at the
:doc:`tools chapter <../reference/tools>` for inspiration how to setup the cli.

View File

@@ -1,6 +1,16 @@
Annotations Reference
=====================
.. warning::
The annotation driver is deprecated and will be removed in version
3.0. It is strongly recommended to switch to one of the other
mapping drivers.
.. note::
To be able to use annotations, you will have to install an extra
package called ``doctrine/annotations``.
You've probably used docblock annotations in some form already,
most likely to provide documentation metadata for a tool like
``PHPDocumentor`` (@author, @link, ...). Docblock annotations are a
@@ -13,12 +23,15 @@ chances of clashes with other docblock annotations, the Doctrine ORM
docblock annotations feature an alternative syntax that is heavily
inspired by the Annotation syntax introduced in Java 5.
The implementation of these enhanced docblock annotations is
located in the ``Doctrine\Common\Annotations`` namespace and
therefore part of the Common package. Doctrine ORM docblock
annotations support namespaces and nested annotations among other
things. The Doctrine ORM ORM defines its own set of docblock
annotations for supplying object-relational mapping metadata.
The implementation of these enhanced docblock annotations is located in
the ``doctrine/annotations`` package, but in the
``Doctrine\Common\Annotations`` namespace for backwards compatibility
reasons. Note that ``doctrine/annotations`` is not required by Doctrine
ORM, and you will need to require that package if you want to use
annotations. Doctrine ORM docblock annotations support namespaces and
nested annotations among other things. The Doctrine ORM defines its
own set of docblock annotations for supplying object-relational mapping
metadata.
.. note::
@@ -89,7 +102,7 @@ as part of the lifecycle of the instance variables entity-class.
Required attributes:
- **type**: Name of the Doctrine Type which is converted between PHP
and Database representation.
and Database representation. Default to ``string`` or :ref:`Type from PHP property type <reference-php-mapping-types>`
Optional attributes:
@@ -115,6 +128,18 @@ Optional attributes:
- **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false.
- **insertable**: Boolean value to determine if the column should be
included when inserting a new row into the underlying entities table.
If not specified, default value is true.
- **updatable**: Boolean value to determine if the column should be
included when updating the row of the underlying entities table.
If not specified, default value is true.
- **generated**: An enum with the possible values ALWAYS, INSERT, NEVER. Is
used after an INSERT or UPDATE statement to determine if the database
generated this value and it needs to be fetched using a SELECT statement.
- **options**: Array of additional options:
- ``default``: The default value to set for the column if no value
@@ -185,6 +210,13 @@ Examples:
*/
protected $loginCount;
/**
* Generated column
* @Column(type="string", name="user_fullname", insertable=false, updatable=false)
* MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)),
*/
protected $fullname;
.. _annref_column_result:
@ColumnResult
@@ -350,7 +382,7 @@ in order to specify that it is an embedded class.
Required attributes:
- **class**: The embeddable class
- **class**: The embeddable class. You can omit this value if you use a PHP property type instead.
.. code-block:: php
@@ -398,11 +430,11 @@ Example:
<?php
/**
* @Entity(repositoryClass="MyProject\UserRepository")
* @Entity(repositoryClass="MyProject\UserRepository", readOnly=true)
*/
class User
{
//...
// ...
}
.. _annref_entity_result:
@@ -455,7 +487,8 @@ Optional attributes:
- **strategy**: Set the name of the identifier generation strategy.
Valid values are AUTO, SEQUENCE, TABLE, IDENTITY, UUID, CUSTOM and NONE.
Valid values are ``AUTO``, ``SEQUENCE``, ``IDENTITY``, ``UUID`` (deprecated), ``CUSTOM`` and ``NONE``, explained
in the :ref:`Identifier Generation Strategies <identifier-generation-strategies>` section.
If not specified, default value is AUTO.
Example:
@@ -512,11 +545,12 @@ has meaning in the SchemaTool schema generation context.
Required attributes:
- **name**: Name of the Index
- **columns**: Array of columns.
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
Optional attributes:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
@@ -535,6 +569,19 @@ Basic example:
{
}
Basic example using fields:
.. code-block:: php
<?php
/**
* @Entity
* @Table(name="ecommerce_products",indexes={@Index(name="search_idx", fields={"name", "email"})})
*/
class ECommerceProduct
{
}
Example with partial indexes:
.. code-block:: php
@@ -715,6 +762,7 @@ Required attributes:
- **targetEntity**: FQCN of the referenced target entity. Can be the
unqualified class name if both classes are in the same namespace.
You can omit this value if you use a PHP property type instead.
*IMPORTANT:* No leading backslash!
Optional attributes:
@@ -840,6 +888,11 @@ Example:
@NamedNativeQuery
~~~~~~~~~~~~~~~~~
.. note::
Named Native Queries are deprecated as of version 2.9 and will be removed in ORM 3.0
Is used to specify a native SQL named query.
The NamedNativeQuery annotation can be applied to an entity or mapped superclass.
@@ -923,6 +976,7 @@ Required attributes:
- **targetEntity**: FQCN of the referenced target entity. Can be the
unqualified class name if both classes are in the same namespace.
When typed properties are used it is inherited from PHP type.
*IMPORTANT:* No leading backslash!
Optional attributes:
@@ -1262,11 +1316,12 @@ context.
Required attributes:
- **name**: Name of the Index
- **columns**: Array of columns.
- **fields**: Array of fields. Exactly one of **fields**, **columns** is required.
- **columns**: Array of columns. Exactly one of **fields**, **columns** is required.
Optional attributes:
- **name**: Name of the Index. If not provided, a generated name will be assigned.
- **options**: Array of platform specific options:
- ``where``: SQL WHERE condition to be used for partial indexes. It will
@@ -1285,6 +1340,19 @@ Basic example:
{
}
Basic example using fields:
.. code-block:: php
<?php
/**
* @Entity
* @Table(name="ecommerce_products",uniqueConstraints={@UniqueConstraint(name="search_idx", fields={"name", "email"})})
*/
class ECommerceProduct
{
}
Example with partial indexes:
.. code-block:: php
@@ -1319,4 +1387,3 @@ Example:
* @Version
*/
protected $version;

View File

@@ -66,33 +66,21 @@ The root namespace of the ORM package is ``Doctrine\ORM``.
Terminology
-----------
.. _terminology_entities:
Entities
~~~~~~~~
An entity is a lightweight, persistent domain object. An entity can
be any regular PHP class observing the following restrictions:
- An entity class must not be final or contain final methods.
- All persistent properties/field of any entity class should
always be private or protected, otherwise lazy-loading might not
work as expected. In case you serialize entities (for example Session)
properties should be protected (See Serialize section below).
- An entity class must not implement ``__clone`` or
:doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`.
- An entity class must not implement ``__wakeup`` or
:doc:`do so safely <../cookbook/implementing-wakeup-or-clone>`.
Also consider implementing
`Serializable <http://php.net/manual/en/class.serializable.php>`_
instead.
- An entity class must not be final nor read-only but
it may contain final methods or read-only properties.
- Any two entity classes in a class hierarchy that inherit
directly or indirectly from one another must not have a mapped
property with the same name. That is, if B inherits from A then B
must not have a mapped field with the same name as an already
mapped field that is inherited from A.
- An entity cannot make use of func_get_args() to implement variable parameters.
Generated proxies do not support this for performance reasons and your code might
actually fail to work when violating this restriction.
Entities support inheritance, polymorphic associations, and
polymorphic queries. Both abstract and concrete classes can be
@@ -106,6 +94,25 @@ classes, and non-entity classes may extend entity classes.
never calls entity constructors, thus you are free to use them as
you wish and even have it require arguments of any type.
Mapped Superclasses
~~~~~~~~~~~~~~~~~~~
A mapped superclass is an abstract or concrete class that provides
persistent entity state and mapping information for its subclasses,
but which is not itself an entity.
Mapped superclasses are explained in greater detail in the chapter
on :doc:`inheritance mapping </reference/inheritance-mapping>`.
Transient Classes
~~~~~~~~~~~~~~~~~
The term "transient class" appears in some places in the mapping
drivers as well as the code dealing with metadata handling.
A transient class is a class that is neither an entity nor a mapped
superclass. From the ORM's point of view, these classes can be
completely ignored, and no class metadata is loaded for them at all.
Entity states
~~~~~~~~~~~~~
@@ -152,16 +159,13 @@ Serializing entities
Serializing entities can be problematic and is not really
recommended, at least not as long as an entity instance still holds
references to proxy objects or is still managed by an
EntityManager. If you intend to serialize (and unserialize) entity
instances that still hold references to proxy objects you may run
into problems with private properties because of technical
limitations. Proxy objects implement ``__sleep`` and it is not
possible for ``__sleep`` to return names of private properties in
parent classes. On the other hand it is not a solution for proxy
objects to implement ``Serializable`` because Serializable does not
work well with any potential cyclic object references (at least we
did not find a way yet, if you did, please contact us).
references to proxy objects or is still managed by an EntityManager.
By default, serializing proxy objects does not initialize them. On
unserialization, resulting objects are detached from the entity
manager and cannot be initialiazed anymore. You can implement the
``__serialize()`` method if you want to change that behavior, but
then you need to ensure that you won't generate large serialized
object graphs and take care of circular associations.
The EntityManager
~~~~~~~~~~~~~~~~~
@@ -184,12 +188,14 @@ 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
~~~~~~~~~~~~~~~~
Internally an ``EntityManager`` uses a ``UnitOfWork``, which is a
typical implementation of the
`Unit of Work pattern <http://martinfowler.com/eaaCatalog/unitOfWork.html>`_,
`Unit of Work pattern <https://martinfowler.com/eaaCatalog/unitOfWork.html>`_,
to keep track of all the things that need to be done the next time
``flush`` is invoked. You usually do not directly interact with a
``UnitOfWork`` but with the ``EntityManager`` instead.

View File

@@ -22,9 +22,9 @@ One tip for working with relations is to read the relation from left to right, w
- ManyToOne - Many instances of the current Entity refer to One instance of the referred Entity.
- OneToOne - One instance of the current Entity refers to One instance of the referred Entity.
See below for all the possible relations.
See below for all the possible relations.
An association is considered to be unidirectional if only one side of the association has
An association is considered to be unidirectional if only one side of the association has
a property referring to the other side.
To gain a full understanding of associations you should also read about :doc:`owning and
@@ -37,7 +37,26 @@ A many-to-one association is the most common association between objects. Exampl
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
// ...
#[ManyToOne(targetEntity: Address::class)]
#[JoinColumn(name: 'address_id', referencedColumnName: 'id')]
private Address|null $address = null;
}
#[Entity]
class Address
{
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -49,7 +68,7 @@ A many-to-one association is the most common association between objects. Exampl
* @ManyToOne(targetEntity="Address")
* @JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
private Address|null $address = null;
}
/** @Entity */
@@ -82,9 +101,11 @@ A many-to-one association is the most common association between objects. Exampl
.. note::
The above ``@JoinColumn`` is optional as it would default
The above ``#[JoinColumn]`` is optional as it would default
to ``address_id`` and ``id`` anyways. You can omit it and let it
use the defaults.
Likewise, inside the ``#[ManyToOne]`` attribute you can omit the
``targetEntity`` argument and it will default to ``Address``.
Generated MySQL Schema:
@@ -111,7 +132,29 @@ references one ``Shipment`` entity.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class Product
{
// ...
/** One Product has One Shipment. */
#[OneToOne(targetEntity: Shipment::class)]
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
private Shipment|null $shipment = null;
// ...
}
#[Entity]
class Shipment
{
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -124,7 +167,7 @@ references one ``Shipment`` entity.
* @OneToOne(targetEntity="Shipment")
* @JoinColumn(name="shipment_id", referencedColumnName="id")
*/
private $shipment;
private Shipment|null $shipment = null;
// ...
}
@@ -156,7 +199,7 @@ references one ``Shipment`` entity.
name: shipment_id
referencedColumnName: id
Note that the @JoinColumn is not really necessary in this example,
Note that the ``#[JoinColumn]`` is not really necessary in this example,
as the defaults would be the same.
Generated MySQL Schema:
@@ -182,13 +225,41 @@ Here is a one-to-one relationship between a ``Customer`` and a
``Cart``. The ``Cart`` has a reference back to the ``Customer`` so
it is bidirectional.
Here we see the ``mappedBy`` and ``inversedBy`` annotations for the first time.
Here we see the ``mappedBy`` and ``inversedBy`` attributes for the first time.
They are used to tell Doctrine which property on the other side refers to the
object.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class Customer
{
// ...
/** One Customer has One Cart. */
#[OneToOne(targetEntity: Cart::class, mappedBy: 'customer')]
private Cart|null $cart = null;
// ...
}
#[Entity]
class Cart
{
// ...
/** One Cart has One Customer. */
#[OneToOne(targetEntity: Customer::class, inversedBy: 'cart')]
#[JoinColumn(name: 'customer_id', referencedColumnName: 'id')]
private Customer|null $customer = null;
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -200,7 +271,7 @@ object.
* One Customer has One Cart.
* @OneToOne(targetEntity="Cart", mappedBy="customer")
*/
private $cart;
private Cart|null $cart = null;
// ...
}
@@ -215,7 +286,7 @@ object.
* @OneToOne(targetEntity="Customer", inversedBy="cart")
* @JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
private Customer|null $customer = null;
// ...
}
@@ -259,6 +330,7 @@ Generated MySQL Schema:
CREATE TABLE Cart (
id INT AUTO_INCREMENT NOT NULL,
customer_id INT DEFAULT NULL,
UNIQUE INDEX UNIQ_BA388B79395C3F3 (customer_id),
PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE Customer (
@@ -280,17 +352,15 @@ below.
.. code-block:: php
<?php
/** @Entity */
#[Entity]
class Student
{
// ...
/**
* One Student has One Mentor.
* @OneToOne(targetEntity="Student")
* @JoinColumn(name="mentor_id", referencedColumnName="id")
*/
private $mentor;
/** One Student has One Mentor. */
#[OneToOne(targetEntity: Student::class)]
#[JoinColumn(name: 'mentor_id', referencedColumnName: 'id')]
private Student|null $mentor = null;
// ...
}
@@ -325,7 +395,40 @@ bidirectional many-to-one.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
use Doctrine\Common\Collections\ArrayCollection;
#[Entity]
class Product
{
// ...
/**
* One product has many features. This is the inverse side.
* @var Collection<int, Feature>
*/
#[OneToMany(targetEntity: Feature::class, mappedBy: 'product')]
private Collection $features;
// ...
public function __construct() {
$this->features = new ArrayCollection();
}
}
#[Entity]
class Feature
{
// ...
/** Many features have one product. This is the owning side. */
#[ManyToOne(targetEntity: Product::class, inversedBy: 'features')]
#[JoinColumn(name: 'product_id', referencedColumnName: 'id')]
private Product|null $product = null;
// ...
}
.. code-block:: annotation
<?php
use Doctrine\Common\Collections\ArrayCollection;
@@ -336,9 +439,10 @@ bidirectional many-to-one.
// ...
/**
* One product has many features. This is the inverse side.
* @var Collection<int, Feature>
* @OneToMany(targetEntity="Feature", mappedBy="product")
*/
private $features;
private Collection $features;
// ...
public function __construct() {
@@ -355,7 +459,7 @@ bidirectional many-to-one.
* @ManyToOne(targetEntity="Product", inversedBy="features")
* @JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
private Product|null $product = null;
// ...
}
@@ -420,7 +524,39 @@ The following example sets up such a unidirectional one-to-many association:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
// ...
/**
* Many Users have Many Phonenumbers.
* @var Collection<int, Phonenumber>
*/
#[JoinTable(name: 'users_phonenumbers')]
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
#[InverseJoinColumn(name: 'phonenumber_id', referencedColumnName: 'id', unique: true)]
#[ManyToMany(targetEntity: 'Phonenumber')]
private Collection $phonenumbers;
public function __construct()
{
$this->phonenumbers = new ArrayCollection();
}
// ...
}
#[Entity]
class Phonenumber
{
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -429,14 +565,15 @@ 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")},
* inverseJoinColumns={@JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)}
* )
* @var Collection<int, Phonenumber>
*/
private $phonenumbers;
private Collection $phonenumbers;
public function __construct()
{
@@ -522,7 +659,32 @@ database perspective is known as an adjacency list approach.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class Category
{
// ...
/**
* One Category has Many Categories.
* @var Collection<int, Category>
*/
#[OneToMany(targetEntity: Category::class, mappedBy: 'parent')]
private Collection $children;
/** Many Categories have One Category. */
#[ManyToOne(targetEntity: Category::class, inversedBy: 'children')]
#[JoinColumn(name: 'parent_id', referencedColumnName: 'id')]
private Category|null $parent = null;
// ...
public function __construct() {
$this->children = new ArrayCollection();
}
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -532,15 +694,16 @@ database perspective is known as an adjacency list approach.
/**
* One Category has Many Categories.
* @OneToMany(targetEntity="Category", mappedBy="parent")
* @var Collection<int, Category>
*/
private $children;
private Collection $children;
/**
* Many Categories have One Category.
* @ManyToOne(targetEntity="Category", inversedBy="children")
* @JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
private Category|null $parent = null;
// ...
public function __construct() {
@@ -593,7 +756,38 @@ entities:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
// ...
/**
* Many Users have Many Groups.
* @var Collection<int, Group>
*/
#[JoinTable(name: 'users_groups')]
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
#[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
#[ManyToMany(targetEntity: Group::class)]
private Collection $groups;
// ...
public function __construct() {
$this->groups = new ArrayCollection();
}
}
#[Entity]
class Group
{
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -608,8 +802,9 @@ entities:
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
* )
* @var Collection<int, Group>
*/
private $groups;
private Collection $groups;
// ...
@@ -686,6 +881,15 @@ Generated MySQL Schema:
replaced by one-to-many/many-to-one associations between the 3
participating classes.
.. note::
For many-to-many associations, the ORM takes care of managing rows
in the join table connecting both sides. Due to the way it deals
with entity removals, database-level constraints may not work the
way one might intuitively assume. Thus, be sure not to miss the section
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
Many-To-Many, Bidirectional
---------------------------
@@ -694,7 +898,48 @@ one is bidirectional.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
// ...
/**
* Many Users have Many Groups.
* @var Collection<int, Group>
*/
#[ManyToMany(targetEntity: Group::class, inversedBy: 'users')]
#[JoinTable(name: 'users_groups')]
private Collection $groups;
public function __construct() {
$this->groups = new ArrayCollection();
}
// ...
}
#[Entity]
class Group
{
// ...
/**
* Many Groups have Many Users.
* @var Collection<int, User>
*/
#[ManyToMany(targetEntity: User::class, mappedBy: 'groups')]
private Collection $users;
public function __construct() {
$this->users = new ArrayCollection();
}
// ...
}
.. code-block:: annotation
<?php
/** @Entity */
@@ -706,8 +951,9 @@ one is bidirectional.
* Many Users have Many Groups.
* @ManyToMany(targetEntity="Group", inversedBy="users")
* @JoinTable(name="users_groups")
* @var Collection<int, Group>
*/
private $groups;
private Collection $groups;
public function __construct() {
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
@@ -723,8 +969,9 @@ one is bidirectional.
/**
* Many Groups have Many Users.
* @ManyToMany(targetEntity="User", mappedBy="groups")
* @var Collection<int, User>
*/
private $users;
private Collection $users;
public function __construct() {
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
@@ -781,6 +1028,15 @@ one is bidirectional.
The MySQL schema is exactly the same as for the Many-To-Many
uni-directional case above.
.. note::
For many-to-many associations, the ORM takes care of managing rows
in the join table connecting both sides. Due to the way it deals
with entity removals, database-level constraints may not work the
way one might intuitively assume. Thus, be sure not to miss the section
on :ref:`join table management <remove_object_many_to_many_join_tables>`.
Owning and Inverse Side on a ManyToMany Association
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -805,9 +1061,9 @@ understandable:
<?php
class Article
{
private $tags;
private Collection $tags;
public function addTag(Tag $tag)
public function addTag(Tag $tag): void
{
$tag->addArticle($this); // synchronously updating inverse side
$this->tags[] = $tag;
@@ -816,9 +1072,9 @@ understandable:
class Tag
{
private $articles;
private Collection $articles;
public function addArticle(Article $article)
public function addArticle(Article $article): void
{
$this->articles[] = $article;
}
@@ -846,30 +1102,31 @@ field named ``$friendsWithMe`` and ``$myFriends``.
.. code-block:: php
<?php
/** @Entity */
#[Entity]
class User
{
// ...
/**
* Many Users have Many Users.
* @ManyToMany(targetEntity="User", mappedBy="myFriends")
* @var Collection<int, User>
*/
private $friendsWithMe;
#[ManyToMany(targetEntity: User::class, mappedBy: 'myFriends')]
private Collection $friendsWithMe;
/**
* Many Users have many Users.
* @ManyToMany(targetEntity="User", inversedBy="friendsWithMe")
* @JoinTable(name="friends",
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="friend_user_id", referencedColumnName="id")}
* )
* @var Collection<int, User>
*/
private $myFriends;
#[JoinTable(name: 'friends')]
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
#[InverseJoinColumn(name: 'friend_user_id', referencedColumnName: 'id')]
#[ManyToMany(targetEntity: 'User', inversedBy: 'friendsWithMe')]
private Collection $myFriends;
public function __construct() {
$this->friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection();
$this->myFriends = new \Doctrine\Common\Collections\ArrayCollection();
$this->friendsWithMe = new ArrayCollection();
$this->myFriends = new ArrayCollection();
}
// ...
@@ -909,11 +1166,17 @@ As an example, consider this mapping:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[OneToOne(targetEntity: Shipment::class)]
private Shipment|null $shipment = null;
.. code-block:: annotation
<?php
/** @OneToOne(targetEntity="Shipment") */
private $shipment;
private Shipment|null $shipment = null;
.. code-block:: xml
@@ -936,7 +1199,15 @@ mapping:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
/** One Product has One Shipment. */
#[OneToOne(targetEntity: Shipment::class)]
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id')]
private Shipment|null $shipment = null;
.. code-block:: annotation
<?php
/**
@@ -944,7 +1215,7 @@ mapping:
* @OneToOne(targetEntity="Shipment")
* @JoinColumn(name="shipment_id", referencedColumnName="id")
*/
private $shipment;
private Shipment|null $shipment = null;
.. code-block:: xml
@@ -972,15 +1243,30 @@ similar defaults. As an example, consider this mapping:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class User
{
//...
/** @ManyToMany(targetEntity="Group") */
private $groups;
//...
// ...
/** @var Collection<int, Group> */
#[ManyToMany(targetEntity: Group::class)]
private Collection $groups;
// ...
}
.. code-block:: annotation
<?php
class User
{
// ...
/**
* @ManyToMany(targetEntity="Group")
* @var Collection<int, Group>
*/
private Collection $groups;
// ...
}
.. code-block:: xml
@@ -1003,12 +1289,30 @@ This is essentially the same as the following, more verbose, mapping:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class User
{
//...
// ...
/**
* Many Users have Many Groups.
* @var Collection<int, Group>
*/
#[JoinTable(name: 'User_Group')]
#[JoinColumn(name: 'User_id', referencedColumnName: 'id')]
#[InverseJoinColumn(name: 'Group_id', referencedColumnName: 'id')]
#[ManyToMany(targetEntity: Group::class)]
private Collection $groups;
// ...
}
.. code-block:: annotation
<?php
class User
{
// ...
/**
* Many Users have Many Groups.
* @ManyToMany(targetEntity="Group")
@@ -1016,9 +1320,10 @@ This is essentially the same as the following, more verbose, mapping:
* joinColumns={@JoinColumn(name="User_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="Group_id", referencedColumnName="id")}
* )
* @var Collection<int, Group>
*/
private $groups;
//...
private Collection $groups;
// ...
}
.. code-block:: xml
@@ -1061,6 +1366,84 @@ join columns default to the simple, unqualified class name of the
targeted class followed by "\_id". The referencedColumnName always
defaults to "id", just as in one-to-one or many-to-one mappings.
Additionally, when using typed properties with Doctrine 2.9 or newer
you can skip ``targetEntity`` in ``ManyToOne`` and ``OneToOne``
associations as they will be set based on type. Also ``nullable``
attribute on ``JoinColumn`` will be inherited from PHP type. So that:
.. configuration-block::
.. code-block:: attribute
<?php
#[OneToOne]
private Shipment $shipment;
.. code-block:: annotation
<?php
/** @OneToOne */
private Shipment $shipment;
.. code-block:: xml
<doctrine-mapping>
<entity class="Product">
<one-to-one field="shipment" />
</entity>
</doctrine-mapping>
.. code-block:: yaml
Product:
type: entity
oneToOne:
shipment: ~
Is essentially the same as following:
.. configuration-block::
.. code-block:: attribute
<?php
/** One Product has One Shipment. */
#[OneToOne(targetEntity: Shipment::class)]
#[JoinColumn(name: 'shipment_id', referencedColumnName: 'id', nullable: false)]
private Shipment $shipment;
.. code-block:: annotation
<?php
/**
* One Product has One Shipment.
* @OneToOne(targetEntity="Shipment")
* @JoinColumn(name="shipment_id", referencedColumnName="id", nullable=false)
*/
private Shipment $shipment;
.. code-block:: xml
<doctrine-mapping>
<entity class="Product">
<one-to-one field="shipment" target-entity="Shipment">
<join-column name="shipment_id" referenced-column-name="id" nulable=false />
</one-to-one>
</entity>
</doctrine-mapping>
.. code-block:: yaml
Product:
type: entity
oneToOne:
shipment:
targetEntity: Shipment
joinColumn:
name: shipment_id
referencedColumnName: id
nullable: false
If you accept these defaults, you can reduce the mapping code to a
minimum.
@@ -1098,22 +1481,19 @@ and ``@ManyToMany`` associations in the constructor of your entities:
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
/** @Entity */
#[Entity]
class User
{
/**
* Many Users have Many Groups.
* @var Collection
* @ManyToMany(targetEntity="Group")
*/
private $groups;
/** Many Users have Many Groups. */
#[ManyToMany(targetEntity: Group::class)]
private Collection $groups;
public function __construct()
{
$this->groups = new ArrayCollection();
}
public function getGroups()
public function getGroups(): Collection
{
return $this->groups;
}

File diff suppressed because it is too large Load Diff

View File

@@ -14,17 +14,11 @@ After working through this guide you should know:
Mapping of associations will be covered in the next chapter on
:doc:`Association Mapping <association-mapping>`.
Guide Assumptions
-----------------
You should have already :doc:`installed and configure <configuration>`
Doctrine.
Creating Classes for the Database
---------------------------------
Every PHP object that you want to save in the database using Doctrine
is called an "Entity". The term "Entity" describes objects
is called an *Entity*. The term "Entity" describes objects
that have an identity over many independent requests. This identity is
usually achieved by assigning a unique identifier to an entity.
In this tutorial the following ``Message`` PHP class will serve as the
@@ -50,19 +44,21 @@ that describes your entity.
Doctrine provides several different ways to specify object-relational
mapping metadata:
- :doc:`Docblock Annotations <annotations-reference>`
- :doc:`Attributes <attributes-reference>`
- :doc:`XML <xml-mapping>`
- :doc:`YAML <yaml-mapping>`
- :doc:`PHP code <php-mapping>`
- :doc:`Docblock Annotations <annotations-reference>` (deprecated and will be removed in ``doctrine/orm`` 3.0)
- :doc:`YAML <yaml-mapping>` (deprecated and will be removed in ``doctrine/orm`` 3.0.)
This manual will usually show mapping metadata via docblock annotations, though
many examples also show the equivalent configuration in YAML and XML.
This manual will usually show mapping metadata via attributes, though
many examples also show the equivalent configuration in annotations,
YAML and XML.
.. note::
All metadata drivers perform equally. Once the metadata of a class has been
read from the source (annotations, xml or yaml) it is stored in an instance
of the ``Doctrine\ORM\Mapping\ClassMetadata`` class and these instances are
read from the source (attributes, annotations, XML, etc.) it is stored in an instance
of the ``Doctrine\ORM\Mapping\ClassMetadata`` class which are
stored in the metadata cache. If you're not using a metadata cache (not
recommended!) then the XML driver is the fastest.
@@ -70,13 +66,26 @@ Marking our ``Message`` class as an entity for Doctrine is straightforward:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
use Doctrine\ORM\Mapping\Entity;
#[Entity]
class Message
{
// ...
}
.. code-block:: annotation
<?php
use Doctrine\ORM\Mapping\Entity;
/** @Entity */
class Message
{
//...
// ...
}
.. code-block:: xml
@@ -99,16 +108,32 @@ You can change this by configuring information about the table:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
#[Entity]
#[Table(name: 'message')]
class Message
{
// ...
}
.. code-block:: annotation
<?php
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
/**
* @Entity
* @Table(name="message")
*/
class Message
{
//...
// ...
}
.. code-block:: xml
@@ -131,19 +156,38 @@ Now the class ``Message`` will be saved and fetched from the table ``message``.
Property Mapping
----------------
The next step after marking a PHP class as an entity is mapping its properties
to columns in a table.
The next step is mapping its properties to columns in the table.
To configure a property use the ``@Column`` docblock annotation. The ``type``
attribute specifies the :ref:`Doctrine Mapping Type <reference-mapping-types>`
to use for the field. If the type is not specified, ``string`` is used as the
default.
To configure a property use the ``Column`` attribute. The ``type``
argument specifies the :ref:`Doctrine Mapping Type
<reference-mapping-types>` to use for the field. If the type is not
specified, ``string`` is used as the default.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
use Doctrine\ORM\Mapping\Column;
use Doctrine\DBAL\Types\Types;
#[Entity]
class Message
{
#[Column(type: Types::INTEGER)]
private $id;
#[Column(length: 140)]
private $text;
#[Column(name: 'posted_at', type: Types::DATETIME)]
private $postedAt;
}
.. code-block:: annotation
<?php
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Column;
/** @Entity */
class Message
{
@@ -179,38 +223,78 @@ default.
column: posted_at
When we don't explicitly specify a column name via the ``name`` option, Doctrine
assumes the field name is also the column name. This means that:
assumes the field name is also the column name. So in this example:
* the ``id`` property will map to the column ``id`` using the type ``integer``;
* the ``text`` property will map to the column ``text`` with the default mapping type ``string``;
* the ``postedAt`` property will map to the ``posted_at`` column with the ``datetime`` type.
The Column annotation has some more attributes. Here is a complete
list:
Here is a complete list of ``Column``s attributes (all optional):
- ``type``: (optional, defaults to 'string') The mapping type to
use for the column.
- ``name``: (optional, defaults to field name) The name of the
column in the database.
- ``length``: (optional, default 255) The length of the column in
the database. (Applies only if a string-valued column is used).
- ``unique``: (optional, default FALSE) Whether the column is a
unique key.
- ``nullable``: (optional, default FALSE) Whether the database
column is nullable.
- ``precision``: (optional, default 0) The precision for a decimal
(exact numeric) column (applies only for decimal column),
- ``type`` (default: 'string'): The mapping type to use for the column.
- ``name`` (default: name of property): The name of the column in the database.
- ``length`` (default: 255): The length of the column in the database.
Applies only if a string-valued column is used.
- ``unique`` (default: ``false``): Whether the column is a unique key.
- ``nullable`` (default: ``false``): Whether the column is nullable.
- ``insertable`` (default: ``true``): Whether the column should be inserted.
- ``updatable`` (default: ``true``): Whether the column should be updated.
- ``enumType`` (requires PHP 8.1 and ``doctrine/orm`` 2.11): The PHP enum class name to convert the database value into.
- ``precision`` (default: 0): The precision for a decimal (exact numeric) column
(applies only for decimal column),
which is the maximum number of digits that are stored for the values.
- ``scale``: (optional, default 0) The scale for a decimal (exact
- ``scale`` (default: 0): The scale for a decimal (exact
numeric) column (applies only for decimal column), which represents
the number of digits to the right of the decimal point and must
not be greater than *precision*.
- ``columnDefinition``: (optional) Allows to define a custom
not be greater than ``precision``.
- ``columnDefinition``: Allows to define a custom
DDL snippet that is used to create the column. Warning: This normally
confuses the SchemaTool to always detect the column as changed.
- ``options``: (optional) Key-value pairs of options that get passed
confuses the :doc:`SchemaTool <tools>` to always detect the column as changed.
- ``options``: Key-value pairs of options that get passed
to the underlying database platform when generating DDL statements.
.. _reference-php-mapping-types:
PHP Types Mapping
_________________
.. versionadded:: 2.9
The column types can be inferred automatically from PHP's property types.
However, when the property type is nullable this has no effect on the ``nullable`` Column attribute.
These are the "automatic" mapping rules:
+-----------------------+-------------------------------+
| PHP property type | Doctrine column type |
+=======================+===============================+
| ``DateInterval`` | ``Types::DATEINTERVAL`` |
+-----------------------+-------------------------------+
| ``DateTime`` | ``Types::DATETIME_MUTABLE`` |
+-----------------------+-------------------------------+
| ``DateTimeImmutable`` | ``Types::DATETIME_IMMUTABLE`` |
+-----------------------+-------------------------------+
| ``array`` | ``Types::JSON`` |
+-----------------------+-------------------------------+
| ``bool`` | ``Types::BOOLEAN`` |
+-----------------------+-------------------------------+
| ``float`` | ``Types::FLOAT`` |
+-----------------------+-------------------------------+
| ``int`` | ``Types::INTEGER`` |
+-----------------------+-------------------------------+
| Any other type | ``Types::STRING`` |
+-----------------------+-------------------------------+
As of version 2.11 Doctrine can also automatically map typed properties using a
PHP 8.1 enum to set the right ``type`` and ``enumType``.
.. versionadded:: 2.14
Since version 2.14 you can specify custom typed field mapping between PHP type and DBAL type using ``Configuration``
and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
:doc:`Read more about TypedFieldMapper <typedfieldmapper>`.
.. _reference-mapping-types:
Doctrine Mapping Types
@@ -270,7 +354,7 @@ A cookbook article shows how to define :doc:`your own custom mapping types
.. warning::
All Date types assume that you are exclusively using the default timezone
set by `date_default_timezone_set() <http://php.net/manual/en/function.date-default-timezone-set.php>`_
set by `date_default_timezone_set() <https://php.net/manual/en/function.date-default-timezone-set.php>`_
or by the php.ini configuration ``date.timezone``. Working with
different timezones will cause troubles and unexpected behavior.
@@ -284,12 +368,23 @@ Identifiers / Primary Keys
--------------------------
Every entity class must have an identifier/primary key. You can select
the field that serves as the identifier with the ``@Id``
annotation.
the field that serves as the identifier with the ``#[Id]`` attribute.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class Message
{
#[Id]
#[Column(type: 'integer')]
#[GeneratedValue]
private int|null $id = null;
// ...
}
.. code-block:: annotation
<?php
class Message
@@ -299,8 +394,8 @@ annotation.
* @Column(type="integer")
* @GeneratedValue
*/
private $id;
//...
private int|null $id = null;
// ...
}
.. code-block:: xml
@@ -326,11 +421,13 @@ annotation.
fields:
# fields here
In most cases using the automatic generator strategy (``@GeneratedValue``) is
In most cases using the automatic generator strategy (``#[GeneratedValue]``) is
what you want. It defaults to the identifier generation mechanism your current
database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL
database vendor prefers: AUTO_INCREMENT with MySQL, sequences with PostgreSQL
and Oracle and so on.
.. _identifier-generation-strategies:
Identifier Generation Strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -355,17 +452,14 @@ Here is the list of possible generation strategies:
strategy does currently not provide full portability and is
supported by the following platforms: MySQL/SQLite/SQL Anywhere
(AUTO\_INCREMENT), MSSQL (IDENTITY) and PostgreSQL (SERIAL).
- ``UUID``: Tells Doctrine to use the built-in Universally Unique Identifier
generator. This strategy provides full portability.
- ``TABLE``: Tells Doctrine to use a separate table for ID
generation. This strategy provides full portability.
***This strategy is not yet implemented!***
- ``UUID`` (deprecated): Tells Doctrine to use the built-in Universally
Unique Identifier generator. This strategy provides full portability.
- ``NONE``: Tells Doctrine that the identifiers are assigned (and
thus generated) by your code. The assignment must take place before
a new entity is passed to ``EntityManager#persist``. NONE is the
same as leaving off the @GeneratedValue entirely.
- ``CUSTOM``: With this option, you can use the ``@CustomIdGenerator`` annotation.
It will allow you to pass a :doc:`class of your own to generate the identifiers.<_annref_customidgenerator>`
same as leaving off the ``#[GeneratedValue]`` entirely.
- ``CUSTOM``: With this option, you can use the ``#[CustomIdGenerator]`` attribute.
It will allow you to pass a :ref:`class of your own to generate the identifiers.<annref_customidgenerator>`
Sequence Generator
^^^^^^^^^^^^^^^^^^
@@ -376,7 +470,19 @@ besides specifying the sequence's name:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class Message
{
#[Id]
#[GeneratedValue(strategy: 'SEQUENCE')]
#[SequenceGenerator(sequenceName: 'message_seq', initialValue: 1, allocationSize: 100)]
protected int|null $id = null;
// ...
}
.. code-block:: annotation
<?php
class Message
@@ -386,8 +492,8 @@ besides specifying the sequence's name:
* @GeneratedValue(strategy="SEQUENCE")
* @SequenceGenerator(sequenceName="message_seq", initialValue=1, allocationSize=100)
*/
protected $id = null;
//...
protected int|null $id = null;
// ...
}
.. code-block:: xml
@@ -427,8 +533,6 @@ the above example with ``allocationSize=100`` Doctrine ORM would only
need to access the sequence once to generate the identifiers for
100 new entities.
*The default allocationSize for a @SequenceGenerator is currently 10.*
.. caution::
The allocationSize is detected by SchemaTool and
@@ -451,11 +555,12 @@ need to access the sequence once to generate the identifiers for
Composite Keys
~~~~~~~~~~~~~~
With Doctrine ORM you can use composite primary keys, using ``@Id`` on more then
one column. Some restrictions exist opposed to using a single identifier in
this case: The use of the ``@GeneratedValue`` annotation is not supported,
which means you can only use composite keys if you generate the primary key
values yourself before calling ``EntityManager#persist()`` on the entity.
With Doctrine ORM you can use composite primary keys, using ``#[Id]`` on
more than one column. Some restrictions exist opposed to using a single
identifier in this case: The use of the ``#[GeneratedValue]`` attribute
is not supported, which means you can only use composite keys if you
generate the primary key values yourself before calling
``EntityManager#persist()`` on the entity.
More details on composite primary keys are discussed in a :doc:`dedicated tutorial
<../tutorials/composite-primary-keys>`.
@@ -471,7 +576,8 @@ needs to be done explicitly using ticks in the definition.
.. code-block:: php
<?php
/** @Column(name="`number`", type="integer") */
#[Column(name: '`number`', type: 'integer')]
private $number;
Doctrine will then quote this column name in all SQL statements

View File

@@ -19,11 +19,13 @@ especially what the strategies presented here provide help with.
.. note::
Having an SQL logger enabled when processing batches can have a serious impact on performance and resource usage.
To avoid that you should disable it in the DBAL configuration:
To avoid that you should remove the corresponding middleware.
To remove all middlewares, you can use this line:
.. code-block:: php
<?php
$em->getConnection()->getConfiguration()->setSQLLogger(null);
$em->getConnection()->getConfiguration()->setMiddlewares([]); // DBAL 3
$em->getConnection()->getConfiguration()->setSQLLogger(null); // DBAL 2
Bulk Inserts
------------
@@ -51,7 +53,7 @@ internally but also mean more work during ``flush``.
$em->clear(); // Detaches all objects from Doctrine!
}
}
$em->flush(); //Persist objects that did not make up an entire batch
$em->flush(); // Persist objects that did not make up an entire batch
$em->clear();
Bulk Updates
@@ -84,16 +86,16 @@ with the batching strategy that was already used for bulk inserts:
<?php
$batchSize = 20;
$i = 1;
$i = 0;
$q = $em->createQuery('select u from MyProject\Model\User u');
foreach ($q->toIterable() as $user) {
$user->increaseCredit();
$user->calculateNewBonuses();
++$i;
if (($i % $batchSize) === 0) {
$em->flush(); // Executes all updates.
$em->clear(); // Detaches all objects from Doctrine!
}
++$i;
}
$em->flush();
@@ -143,15 +145,15 @@ The following example shows how to do this:
<?php
$batchSize = 20;
$i = 1;
$i = 0;
$q = $em->createQuery('select u from MyProject\Model\User u');
foreach($q->toIterable() as $row) {
$em->remove($row);
++$i;
if (($i % $batchSize) === 0) {
$em->flush(); // Executes all deletions.
$em->clear(); // Detaches all objects from Doctrine!
}
++$i;
}
$em->flush();

View File

@@ -74,11 +74,13 @@ collections in entities in the constructor. Example:
<?php
namespace MyProject\Model;
use Doctrine\Common\Collections\ArrayCollection;
class User {
private $addresses;
private $articles;
/** @var Collection<int, Address> */
private Collection $addresses;
/** @var Collection<int, Article> */
private Collection $articles;
public function __construct() {
$this->addresses = new ArrayCollection;
$this->articles = new ArrayCollection;

View File

@@ -1,266 +1,14 @@
Caching
=======
Doctrine provides cache drivers in the ``doctrine/cache`` package for some
of the most popular caching implementations such as APCu, Memcache
and Xcache. We also provide an ``ArrayCache`` driver which stores
the data in a PHP array. Obviously, when using ``ArrayCache``, the
cache does not persist between requests, but this is useful for
testing in a development environment.
The Doctrine ORM package can leverage cache adapters implementing the PSR-6
standard to allow you to improve the performance of various aspects of
Doctrine by simply making some additional configurations and method calls.
Cache Drivers
-------------
.. _types-of-caches:
The cache drivers follow a simple interface that is defined in
``Doctrine\Common\Cache\Cache``. All the cache drivers extend a
base class ``Doctrine\Common\Cache\CacheProvider`` which implements
this interface.
The interface defines the following public methods for you to implement:
- fetch($id) - Fetches an entry from the cache
- contains($id) - Test if an entry exists in the cache
- save($id, $data, $lifeTime = false) - Puts data into the cache for x seconds. 0 = infinite time
- delete($id) - Deletes a cache entry
Each driver extends the ``CacheProvider`` class which defines a few
abstract protected methods that each of the drivers must
implement:
- doFetch($id)
- doContains($id)
- doSave($id, $data, $lifeTime = false)
- doDelete($id)
The public methods ``fetch()``, ``contains()`` etc. use the
above protected methods which are implemented by the drivers. The
code is organized this way so that the protected methods in the
drivers do the raw interaction with the cache implementation and
the ``CacheProvider`` can build custom functionality on top of
these methods.
This documentation does not cover every single cache driver included
with Doctrine. For an up-to-date-list, see the
`cache directory on GitHub <https://github.com/doctrine/cache/tree/master/lib/Doctrine/Common/Cache>`_.
PhpFileCache
~~~~~~~~~~~~
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file. This allows for
opcode caching to be used and provides high performance in most scenarios.
In order to use the ``PhpFileCache`` driver it must be able to write to
a directory.
Below is an example of how to use the ``PhpFileCache`` driver by itself.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$cacheDriver->save('cache_id', 'my_data');
The PhpFileCache is not distributed across multiple machines if you are running
your application in a distributed setup. This is ok for the metadata and query
cache but is not a good approach for the result cache.
Memcache
~~~~~~~~
In order to use the Memcache cache driver you must have it compiled
and enabled in your php.ini. You can read about Memcache
`on the PHP website <http://php.net/memcache>`_. It will
give you a little background information about what it is and how
you can use it as well as how to install it.
Below is a simple example of how you could use the Memcache cache
driver by itself.
.. code-block:: php
<?php
$memcache = new Memcache();
$memcache->connect('memcache_host', 11211);
$cacheDriver = new \Doctrine\Common\Cache\MemcacheCache();
$cacheDriver->setMemcache($memcache);
$cacheDriver->save('cache_id', 'my_data');
Memcached
~~~~~~~~~
Memcached is a more recent and complete alternative extension to
Memcache.
In order to use the Memcached cache driver you must have it compiled
and enabled in your php.ini. You can read about Memcached
`on the PHP website <http://php.net/memcached>`_. It will
give you a little background information about what it is and how
you can use it as well as how to install it.
Below is a simple example of how you could use the Memcached cache
driver by itself.
.. code-block:: php
<?php
$memcached = new Memcached();
$memcached->addServer('memcache_host', 11211);
$cacheDriver = new \Doctrine\Common\Cache\MemcachedCache();
$cacheDriver->setMemcached($memcached);
$cacheDriver->save('cache_id', 'my_data');
Redis
~~~~~
In order to use the Redis cache driver you must have it compiled
and enabled in your php.ini. You can read about what Redis is
`from here <http://redis.io/>`_. Also check
`A PHP extension for Redis <https://github.com/nicolasff/phpredis/>`_ for how you can use
and install the Redis PHP extension.
Below is a simple example of how you could use the Redis cache
driver by itself.
.. code-block:: php
<?php
$redis = new Redis();
$redis->connect('redis_host', 6379);
$cacheDriver = new \Doctrine\Common\Cache\RedisCache();
$cacheDriver->setRedis($redis);
$cacheDriver->save('cache_id', 'my_data');
Using Cache Drivers
-------------------
In this section we'll describe how you can fully utilize the API of
the cache drivers to save data to a cache, check if some cached data
exists, fetch the cached data and delete the cached data. We'll use the
``ArrayCache`` implementation as our example here.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\ArrayCache();
Saving
~~~~~~
Saving some data to the cache driver is as simple as using the
``save()`` method.
.. code-block:: php
<?php
$cacheDriver->save('cache_id', 'my_data');
The ``save()`` method accepts three arguments which are described
below:
- ``$id`` - The cache id
- ``$data`` - The cache entry/data.
- ``$lifeTime`` - The lifetime. If != false, sets a specific
lifetime for this cache entry (null => infinite lifeTime).
You can save any type of data whether it be a string, array,
object, etc.
.. code-block:: php
<?php
$array = array(
'key1' => 'value1',
'key2' => 'value2'
);
$cacheDriver->save('my_array', $array);
Checking
~~~~~~~~
Checking whether cached data exists is very simple: just use the
``contains()`` method. It accepts a single argument which is the ID
of the cache entry.
.. code-block:: php
<?php
if ($cacheDriver->contains('cache_id')) {
echo 'cache exists';
} else {
echo 'cache does not exist';
}
Fetching
~~~~~~~~
Now if you want to retrieve some cache entry you can use the
``fetch()`` method. It also accepts a single argument just like
``contains()`` which is again the ID of the cache entry.
.. code-block:: php
<?php
$array = $cacheDriver->fetch('my_array');
Deleting
~~~~~~~~
As you might guess, deleting is just as easy as saving, checking
and fetching. You can delete by an individual ID, or you can
delete all entries.
By Cache ID
^^^^^^^^^^^
.. code-block:: php
<?php
$cacheDriver->delete('my_array');
All
^^^
If you simply want to delete all cache entries you can do so with
the ``deleteAll()`` method.
.. code-block:: php
<?php
$deleted = $cacheDriver->deleteAll();
Namespaces
~~~~~~~~~~
If you heavily use caching in your application and use it in
multiple parts of your application, or use it in different
applications on the same server you may have issues with cache
naming collisions. This can be worked around by using namespaces.
You can set the namespace a cache driver should use by using the
``setNamespace()`` method.
.. code-block:: php
<?php
$cacheDriver->setNamespace('my_namespace_');
.. _integrating-with-the-orm:
Integrating with the ORM
------------------------
The Doctrine ORM package is tightly integrated with the cache
drivers to allow you to improve the performance of various aspects of
Doctrine by simply making some additional configurations and
method calls.
Types of Caches
---------------
Query Cache
~~~~~~~~~~~
@@ -276,28 +24,27 @@ use on your ORM configuration.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
'/path/to/writable/directory'
);
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter('doctrine_queries');
$config = new \Doctrine\ORM\Configuration();
$config->setQueryCacheImpl($cacheDriver);
$config->setQueryCache($cache);
Result Cache
~~~~~~~~~~~~
The result cache can be used to cache the results of your queries
so that we don't have to query the database or hydrate the data
again after the first time. You just need to configure the result
cache implementation.
so that we don't have to query the database again after the first time.
You just need to configure the result cache implementation.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
'doctrine_results',
0,
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$config->setResultCacheImpl($cacheDriver);
$config->setResultCache($cache);
Now when you're executing DQL queries you can configure them to use
the result cache.
@@ -314,10 +61,12 @@ result cache driver.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
$cache = new \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
'doctrine_results',
0,
'/path/to/writable/directory'
);
$query->setResultCacheDriver($cacheDriver);
$query->setResultCache($cache);
.. note::
@@ -360,8 +109,9 @@ Metadata Cache
~~~~~~~~~~~~~~
Your class metadata can be parsed from a few different sources like
YAML, XML, Annotations, etc. Instead of parsing this information on
each request we should cache it using one of the cache drivers.
YAML, XML, Attributes, Annotations etc. Instead of parsing this
information on each request we should cache it using one of the cache
drivers.
Just like the query and result cache we need to configure it
first.
@@ -369,11 +119,13 @@ first.
.. code-block:: php
<?php
$cacheDriver = new \Doctrine\Common\Cache\PhpFileCache(
$cache = \Symfony\Component\Cache\Adapter\PhpFilesAdapter(
'doctrine_metadata',
0,
'/path/to/writable/directory'
);
$config = new \Doctrine\ORM\Configuration();
$config->setMetadataCacheImpl($cacheDriver);
$config->setMetadataCache($cache);
Now the metadata information will only be parsed once and stored in
the cache driver.
@@ -423,30 +175,15 @@ requested many times in a single PHP request. Even though this data
may be stored in a fast memory cache, often that cache is over a
network link leading to sizable network traffic.
The ChainCache class allows multiple caches to be registered at once.
For example, a per-request ArrayCache can be used first, followed by
a (relatively) slower MemcacheCache if the ArrayCache misses.
ChainCache automatically handles pushing data up to faster caches in
A chain cache class allows multiple caches to be registered at once.
For example, a per-request array cache can be used first, followed by
a (relatively) slower Memcached cache if the array cache misses.
The chain cache automatically handles pushing data up to faster caches in
the chain and clearing data in the entire stack when it is deleted.
A ChainCache takes a simple array of CacheProviders in the order that
they should be used.
.. code-block:: php
$arrayCache = new \Doctrine\Common\Cache\ArrayCache();
$memcache = new Memcache();
$memcache->connect('memcache_host', 11211);
$chainCache = new \Doctrine\Common\Cache\ChainCache([
$arrayCache,
$memcache,
]);
ChainCache itself extends the CacheProvider interface, so it is
possible to create chains of chains. While this may seem like an easy
way to build a simple high-availability cache, ChainCache does not
implement any exception handling so using it as a high-availability
mechanism is not recommended.
Symfony Cache provides such a chain cache. To find out how to use it,
please have a look at the
`Symfony Documentation <https://symfony.com/doc/current/components/cache/adapters/chain_adapter.html>`_.
Cache Slams
-----------
@@ -463,5 +200,3 @@ not letting your users' requests populate the cache.
You can read more about cache slams
`in this blog post <http://notmysock.org/blog/php/user-cache-timebomb.html>`_.

View File

@@ -49,10 +49,9 @@ This policy can be configured as follows:
.. code-block:: php
<?php
/**
* @Entity
* @ChangeTrackingPolicy("DEFERRED_EXPLICIT")
*/
#[Entity]
#[ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
class User
{
// ...
@@ -61,6 +60,11 @@ This policy can be configured as follows:
Notify
~~~~~~
.. note::
The notify change tracking policy is deprecated and will be removed in ORM 3.0.
(\ `Details <https://github.com/doctrine/orm/issues/8383>`_)
This policy is based on the assumption that the entities notify
interested listeners of changes to their properties. For that
purpose, a class that wants to use this policy needs to implement
@@ -73,18 +77,16 @@ follows:
<?php
use Doctrine\Persistence\NotifyPropertyChanged,
Doctrine\Persistence\PropertyChangedListener;
/**
* @Entity
* @ChangeTrackingPolicy("NOTIFY")
*/
#[Entity]
#[ChangeTrackingPolicy('NOTIFY')]
class MyEntity implements NotifyPropertyChanged
{
// ...
private $_listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener)
private array $_listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener): void
{
$this->_listeners[] = $listener;
}
@@ -99,12 +101,12 @@ behaviour:
<?php
// ...
class MyEntity implements NotifyPropertyChanged
{
// ...
protected function _onPropertyChanged($propName, $oldValue, $newValue)
protected function _onPropertyChanged($propName, $oldValue, $newValue): void
{
if ($this->_listeners) {
foreach ($this->_listeners as $listener) {
@@ -112,8 +114,8 @@ behaviour:
}
}
}
public function setData($data)
public function setData($data): void
{
if ($data != $this->data) {
$this->_onPropertyChanged('data', $this->data, $data);
@@ -129,6 +131,32 @@ The check whether the new value is different from the old one is
not mandatory but recommended. That way you also have full control
over when you consider a property changed.
If your entity contains an embeddable, you will need to notify
separately for each property in the embeddable when it changes
for example:
.. code-block:: php
<?php
// ...
class MyEntity implements NotifyPropertyChanged
{
public function setEmbeddable(MyValueObject $embeddable): void
{
if (!$embeddable->equals($this->embeddable)) {
// notice the entityField.embeddableField notation for referencing the property
$this->_onPropertyChanged('embeddable.prop1', $this->embeddable->getProp1(), $embeddable->getProp1());
$this->_onPropertyChanged('embeddable.prop2', $this->embeddable->getProp2(), $embeddable->getProp2());
$this->embeddable = $embeddable;
}
}
}
This would update all the fields of the embeddable, you may wish to
implement a diff method on your embedded object which returns only
the changed fields.
The negative point of this policy is obvious: You need implement an
interface and write some plumbing code. But also note that we tried
hard to keep this notification functionality abstract. Strictly
@@ -147,5 +175,3 @@ The positive point and main advantage of this policy is its
effectiveness. It has the best performance characteristics of the 3
policies with larger units of work and a flush() operation is very
cheap when nothing has changed.

View File

@@ -41,86 +41,80 @@ access point to ORM functionality provided by Doctrine.
// bootstrap.php
require_once "vendor/autoload.php";
use Doctrine\ORM\Tools\Setup;
use Doctrine\DBAL\DriverManager;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\ORMSetup;
$paths = array("/path/to/entity-files");
$paths = ['/path/to/entity-files'];
$isDevMode = false;
// the connection configuration
$dbParams = array(
$dbParams = [
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'foo',
);
];
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$entityManager = EntityManager::create($dbParams, $config);
$config = ORMSetup::createAttributeMetadataConfiguration($paths, $isDevMode);
$connection = DriverManager::getConnection($dbParams, $config);
$entityManager = new EntityManager($connection, $config);
.. note::
The ``ORMSetup`` class has been introduced with ORM 2.12. It's predecessor ``Setup`` is deprecated and will
be removed in version 3.0.
Or if you prefer XML:
.. code-block:: php
<?php
$paths = array("/path/to/xml-mappings");
$config = Setup::createXMLMetadataConfiguration($paths, $isDevMode);
$entityManager = EntityManager::create($dbParams, $config);
$paths = ['/path/to/xml-mappings'];
$config = ORMSetup::createXMLMetadataConfiguration($paths, $isDevMode);
$connection = DriverManager::getConnection($dbParams, $config);
$entityManager = new EntityManager($connection, $config);
Or if you prefer YAML:
.. code-block:: php
<?php
$paths = array("/path/to/yml-mappings");
$config = Setup::createYAMLMetadataConfiguration($paths, $isDevMode);
$entityManager = EntityManager::create($dbParams, $config);
$paths = ['/path/to/yml-mappings'];
$config = ORMSetup::createYAMLMetadataConfiguration($paths, $isDevMode);
$connection = DriverManager::getConnection($dbParams, $config);
$entityManager = new EntityManager($connection, $config);
.. note::
If you want to use yml mapping you should add yaml dependency to your `composer.json`:
::
"symfony/yaml": "*"
Inside the ``Setup`` methods several assumptions are made:
Inside the ``ORMSetup`` 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 ``ArrayAdapter``. Proxy objects are recreated on every request.
- If ``$isDevMode`` is false, check for Caches in the order APCu, Redis (127.0.0.1:6379), Memcache (127.0.0.1:11211) 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.
.. note::
In order to have ``ORMSetup`` configure the cache automatically, the library ``symfony/cache``
has to be installed as a dependency.
If you want to configure Doctrine in more detail, take a look at the :doc:`Advanced Configuration </reference/advanced-configuration>` section.
.. note::
You can learn more about the database connection configuration in the
`Doctrine DBAL connection configuration reference <http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html>`_.
`Doctrine DBAL connection configuration reference <https://docs.doctrine-project.org/projects/doctrine-dbal/en/stable/reference/configuration.html>`_.
Setting up the Commandline Tool
-------------------------------
Doctrine ships with a number of command line tools that are very helpful
during development. You can call this command from the Composer binary
directory:
.. code-block:: sh
$ php vendor/bin/doctrine
You need to register your applications EntityManager to the console tool
to make use of the tasks by creating a ``cli-config.php`` file with the
following content:
.. code-block:: php
<?php
use Doctrine\ORM\Tools\Console\ConsoleRunner;
// replace with file to your own project bootstrap
require_once 'bootstrap.php';
// replace with mechanism to retrieve EntityManager in your app
$entityManager = GetEntityManager();
return ConsoleRunner::createHelperSet($entityManager);
during development. In order to make use of them, create an executable PHP
script in your project as described in the
:doc:`tools chapter <../reference/tools>`.

View File

@@ -1,5 +1,5 @@
Doctrine Query Language
===========================
=======================
DQL stands for Doctrine Query Language and is an Object
Query Language derivative that is very similar to the Hibernate
@@ -180,10 +180,10 @@ not need to lazy load the association with another query.
Doctrine allows you to walk all the associations between
all the objects in your domain model. Objects that were not already
loaded from the database are replaced with lazy load proxy
instances. Non-loaded Collections are also replaced by lazy-load
loaded from the database are replaced with lazy-loading proxy
instances. Non-loaded Collections are also replaced by lazy-loading
instances that fetch all the contained objects upon first access.
However relying on the lazy-load mechanism leads to many small
However relying on the lazy-loading mechanism leads to many small
queries executed against the database, which can significantly
affect the performance of your application. **Fetch Joins** are the
solution to hydrate most or all of the entities that you need in a
@@ -319,11 +319,11 @@ With Nested Conditions in WHERE Clause:
<?php
$query = $em->createQuery('SELECT u FROM ForumUser u WHERE (u.username = :name OR u.username = :name2) AND u.id = :id');
$query->setParameters(array(
$query->setParameters([
'name' => 'Bob',
'name2' => 'Alice',
'id' => 321,
));
]);
$users = $query->getResult(); // array of ForumUser objects
With COUNT DISTINCT:
@@ -487,6 +487,26 @@ where you can generate an arbitrary join with the following syntax:
<?php
$query = $em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
With an arbitrary join the result differs from the joins using a mapped property.
The result of an arbitrary join is an one dimensional array with a mix of the entity from the ``SELECT``
and the joined entity fitting to the filtering of the query. In case of the example with ``User``
and ``Banlist``, it can look like this:
- User
- Banlist
- Banlist
- User
- Banlist
- User
- Banlist
- Banlist
- Banlist
In this form of join, the ``Banlist`` entities found by the filtering in the ``WITH`` part are not fetched by an accessor
method on ``User``, but are already part of the result. In case the accessor method for Banlists is invoked on a User instance,
it loads all the related ``Banlist`` objects corresponding to this ``User``. This change of behaviour needs to be considered
when the DQL is switched to an arbitrary join.
.. note::
The differences between WHERE, WITH and HAVING clauses may be
confusing.
@@ -603,6 +623,13 @@ then phonenumber-id:
...
'nameUpper' => string 'JWAGE' (length=5)
You can also index by a to-one association, which will use the id of
the associated entity (the join column) as the key in the result set:
.. code-block:: sql
SELECT p, u FROM Participant INDEX BY p.user JOIN p.user u WHERE p.event = 3
UPDATE queries
--------------
@@ -643,11 +670,23 @@ The same restrictions apply for the reference of related entities.
.. warning::
DQL DELETE statements are ported directly into a
Database DELETE statement and therefore bypass any events and checks for the
version column if they are not explicitly added to the WHERE clause
of the query. Additionally Deletes of specified entities are *NOT*
cascaded to related entities even if specified in the metadata.
DQL DELETE statements are ported directly into an SQL DELETE statement.
Therefore, some limitations apply:
- Lifecycle events for the affected entities are not executed.
- A cascading ``remove`` operation (as indicated e. g. by ``cascade: ['remove']``
or ``cascade: ['all']`` in the mapping configuration) is not being performed
for associated entities. You can rely on database level cascade operations by
configuring each join column with the ``onDelete`` option.
- Checks for the version column are bypassed if they are not explicitly added
to the WHERE clause of the query.
When you rely on one of these features, one option is to use the
``EntityManager#remove($entity)`` method. This, however, is costly performance-wise:
It means collections and related entities are fetched into memory
(even if they are marked as lazy). Pulling object graphs into memory on cascade
can cause considerable performance overhead, especially when the cascaded collections
are large. Make sure to weigh the benefits and downsides.
Comments in queries
-------------------
@@ -673,29 +712,35 @@ The following functions are supported in SELECT, WHERE and HAVING
clauses:
- IDENTITY(single\_association\_path\_expression [, fieldMapping]) - Retrieve the foreign key column of association of the owning side
- ABS(arithmetic\_expression)
- CONCAT(str1, str2)
- CURRENT\_DATE() - Return the current date
- CURRENT\_TIME() - Returns the current time
- CURRENT\_TIMESTAMP() - Returns a timestamp of the current date
- ``IDENTITY(single_association_path_expression [, fieldMapping])`` -
Retrieve the foreign key column of association of the owning side
- ``ABS(arithmetic_expression)``
- ``CONCAT(str1, str2)``
- ``CURRENT_DATE()`` - Return the current date
- ``CURRENT_TIME()`` - Returns the current time
- ``CURRENT_TIMESTAMP()`` - Returns a timestamp of the current date
and time.
- LENGTH(str) - Returns the length of the given string
- LOCATE(needle, haystack [, offset]) - Locate the first
- ``LENGTH(str)`` - Returns the length of the given string
- ``LOCATE(needle, haystack [, offset])`` - Locate the first
occurrence of the substring in the string.
- LOWER(str) - returns the string lowercased.
- MOD(a, b) - Return a MOD b.
- SIZE(collection) - Return the number of elements in the
- ``LOWER(str)`` - returns the string lowercased.
- ``MOD(a, b)`` - Return a MOD b.
- ``SIZE(collection)`` - Return the number of elements in the
specified collection
- SQRT(q) - Return the square-root of q.
- SUBSTRING(str, start [, length]) - Return substring of given
- ``SQRT(q)`` - Return the square-root of q.
- ``SUBSTRING(str, start [, length])`` - Return substring of given
string.
- TRIM([LEADING \| TRAILING \| BOTH] ['trchar' FROM] str) - Trim
- ``TRIM([LEADING | TRAILING | BOTH] ['trchar' FROM] str)`` - Trim
the string by the given trim char, defaults to whitespaces.
- UPPER(str) - Return the upper-case of the given string.
- DATE_ADD(date, value, unit) - Add the given time to a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)
- DATE_SUB(date, value, unit) - Subtract the given time from a given date. (Supported units are SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR)
- DATE_DIFF(date1, date2) - Calculate the difference in days between date1-date2.
- ``UPPER(str)`` - Return the upper-case of the given string.
- ``DATE_ADD(date, value, unit)`` - Add the given time to a given date.
(Supported units are ``SECOND``, ``MINUTE``, ``HOUR``, ``DAY``,
``WEEK``, ``MONTH``, ``YEAR``)
- ``DATE_SUB(date, value, unit)`` - Subtract the given time from a
given date. (Supported units are ``SECOND``, ``MINUTE``, ``HOUR``,
``DAY``, ``WEEK``, ``MONTH``, ``YEAR``)
- ``DATE_DIFF(date1, date2)`` - Calculate the difference in days
between date1-date2.
Arithmetic operators
~~~~~~~~~~~~~~~~~~~~
@@ -749,7 +794,7 @@ You can register custom DQL functions in your ORM Configuration:
$config->addCustomNumericFunction($name, $class);
$config->addCustomDatetimeFunction($name, $class);
$em = EntityManager::create($dbParams, $config);
$em = new EntityManager($connection, $config);
The functions have to return either a string, numeric or datetime
value depending on the registered function type. As an example we
@@ -761,8 +806,8 @@ classes have to implement the base class :
<?php
namespace MyProject\Query\AST;
use \Doctrine\ORM\Query\AST\Functions\FunctionNode;
use \Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
class MysqlFloor extends FunctionNode
{
@@ -805,7 +850,7 @@ what type of results to expect.
Single Table
~~~~~~~~~~~~
`Single Table Inheritance <http://martinfowler.com/eaaCatalog/singleTableInheritance.html>`_
`Single Table Inheritance <https://martinfowler.com/eaaCatalog/singleTableInheritance.html>`_
is an inheritance mapping strategy where all classes of a hierarchy
are mapped to a single database table. In order to distinguish
which row represents which type in the hierarchy a so-called
@@ -819,36 +864,26 @@ scenario it is a generic Person and Employee example:
<?php
namespace Entities;
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
#[Entity]
#[InheritanceType('SINGLE_TABLE')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => 'Person', 'employee' => 'Employee'])]
class Person
{
/**
* @Id @Column(type="integer")
* @GeneratedValue
*/
protected $id;
#[Id, Column(type: 'integer')]
#[GeneratedValue]
protected int|null $id = null;
/**
* @Column(type="string", length=50)
*/
protected $name;
#[Column(type: 'string', length: 50)]
protected string $name;
// ...
}
/**
* @Entity
*/
#[Entity]
class Employee extends Person
{
/**
* @Column(type="string", length=50)
*/
#[Column(type: 'string', length: 50)]
private $department;
// ...
@@ -898,7 +933,7 @@ entities:
Class Table Inheritance
~~~~~~~~~~~~~~~~~~~~~~~
`Class Table Inheritance <http://martinfowler.com/eaaCatalog/classTableInheritance.html>`_
`Class Table Inheritance <https://martinfowler.com/eaaCatalog/classTableInheritance.html>`_
is an inheritance mapping strategy where each class in a hierarchy
is mapped to several tables: its own table and the tables of all
parent classes. The table of a child class is linked to the table
@@ -914,12 +949,11 @@ table, you just need to change the inheritance type from
.. code-block:: php
<?php
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
#[Entity]
#[InheritanceType('JOINED')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => 'Person', 'employee' => 'Employee'])]
class Person
{
// ...
@@ -1023,7 +1057,7 @@ the Query class. Here they are:
Instead of using these methods, you can alternatively use the
general-purpose method
``Query#execute(array $params = array(), $hydrationMode = Query::HYDRATE_OBJECT)``.
``Query#execute(array $params = [], $hydrationMode = Query::HYDRATE_OBJECT)``.
Using this method you can directly supply the hydration mode as the
second parameter via one of the Query constants. In fact, the
methods mentioned earlier are just convenient shortcuts for the
@@ -1147,10 +1181,11 @@ make best use of the different result formats:
The constants for the different hydration modes are:
- Query::HYDRATE\_OBJECT
- Query::HYDRATE\_ARRAY
- Query::HYDRATE\_SCALAR
- Query::HYDRATE\_SINGLE\_SCALAR
- ``Query::HYDRATE_OBJECT``
- ``Query::HYDRATE_ARRAY``
- ``Query::HYDRATE_SCALAR``
- ``Query::HYDRATE_SINGLE_SCALAR``
- ``Query::HYDRATE_SCALAR_COLUMN``
Object Hydration
^^^^^^^^^^^^^^^^
@@ -1216,7 +1251,7 @@ Scalar Hydration:
1. Fields from classes are prefixed by the DQL alias in the result.
A query of the kind 'SELECT u.name ..' returns a key 'u\_name' in
A query of the kind 'SELECT u.name ..' returns a key 'u_name' in
the result rows.
Single Scalar Hydration
@@ -1239,6 +1274,25 @@ You can use the ``getSingleScalarResult()`` shortcut as well:
<?php
$numArticles = $query->getSingleScalarResult();
Scalar Column Hydration
^^^^^^^^^^^^^^^^^^^^^^^
If you have a query which returns a one-dimensional array of scalar values
you can use scalar column hydration:
.. code-block:: php
<?php
$query = $em->createQuery('SELECT a.id FROM CmsUser u');
$ids = $query->getResult(Query::HYDRATE_SCALAR_COLUMN);
You can use the ``getSingleColumnResult()`` shortcut as well:
.. code-block:: php
<?php
$ids = $query->getSingleColumnResult();
Custom Hydration Modes
^^^^^^^^^^^^^^^^^^^^^^
@@ -1256,7 +1310,7 @@ creating a class which extends ``AbstractHydrator``:
{
protected function _hydrateAll()
{
return $this->_stmt->fetchAll(PDO::FETCH_ASSOC);
return $this->_stmt->fetchAllAssociative();
}
}
@@ -1282,8 +1336,8 @@ There are situations when a query you want to execute returns a
very large result-set that needs to be processed. All the
previously described hydration modes completely load a result-set
into memory which might not be feasible with large result sets. See
the `Batch Processing <batch-processing.html>`_ section on details how
to iterate large result sets.
the :doc:`Batch Processing </reference/batch-processing>` section on
details how to iterate large result sets.
Functions
~~~~~~~~~
@@ -1364,21 +1418,22 @@ userland. However the following few hints are to be used in
userland:
- Query::HINT\_FORCE\_PARTIAL\_LOAD - Allows to hydrate objects
- ``Query::HINT_FORCE_PARTIAL_LOAD`` - Allows to hydrate objects
although not all their columns are fetched. This query hint can be
used to handle memory consumption problems with large result-sets
that contain char or binary data. Doctrine has no way of implicitly
reloading this data. Partially loaded objects have to be passed to
``EntityManager::refresh()`` if they are to be reloaded fully from
the database.
- Query::HINT\_REFRESH - This query is used internally by
the database. This query hint is deprecated and will be removed
in the future (\ `Details <https://github.com/doctrine/orm/issues/8471>`_)
- ``Query::HINT_REFRESH`` - This query is used internally by
``EntityManager::refresh()`` and can be used in userland as well.
If you specify this hint and a query returns the data for an entity
that is already managed by the UnitOfWork, the fields of the
existing entity will be refreshed. In normal operation a result-set
that loads data of an already existing entity is discarded in favor
of the already existing entity.
- Query::HINT\_CUSTOM\_TREE\_WALKERS - An array of additional
- ``Query::HINT_CUSTOM_TREE_WALKERS`` - An array of additional
``Doctrine\ORM\Query\TreeWalker`` instances that are attached to
the DQL query parsing process.
@@ -1464,6 +1519,8 @@ Given that there are 10 users and corresponding addresses in the database the ex
a one-by-one basis once they are accessed.
.. _dql_ebnf_grammar:
EBNF
----
@@ -1492,7 +1549,6 @@ Terminals
- identifier (name, email, ...) must match ``[a-z_][a-z0-9_]*``
- fully_qualified_name (Doctrine\Tests\Models\CMS\CmsUser) matches PHP's fully qualified class names
- aliased_name (CMS:CmsUser) uses two identifiers, one for the namespace alias and one for the class inside it
- string ('foo', 'bar''s house', '%ninja%', ...)
- char ('/', '\\', ' ', ...)
- integer (-1, 0, 1, 34, ...)
@@ -1615,7 +1671,7 @@ From, Join and Index by
RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" (JoinAssociationDeclaration | RangeVariableDeclaration) ["WITH" ConditionalExpression]
IndexBy ::= "INDEX" "BY" StateFieldPathExpression
IndexBy ::= "INDEX" "BY" SingleValuedPathExpression
Select Expressions
~~~~~~~~~~~~~~~~~~
@@ -1658,7 +1714,7 @@ Literal Values
.. code-block:: php
Literal ::= string | char | integer | float | boolean
InParameter ::= Literal | InputParameter
InParameter ::= ArithmeticExpression | InputParameter
Input Parameter
~~~~~~~~~~~~~~~
@@ -1733,7 +1789,7 @@ QUANTIFIED/BETWEEN/COMPARISON/LIKE/NULL/EXISTS
QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
InExpression ::= ArithmeticExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")
InstanceOfParameter ::= AbstractSchemaName | InputParameter
LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char]
@@ -1773,5 +1829,3 @@ Functions
"LOWER" "(" StringPrimary ")" |
"UPPER" "(" StringPrimary ")" |
"IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")"

File diff suppressed because it is too large Load Diff

View File

@@ -13,10 +13,10 @@ Database Schema
How do I set the charset and collation for MySQL tables?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can't set these values inside the annotations, yml or xml mapping files. To make a database
work with the default charset and collation you should configure MySQL to use it as default charset,
or create the database with charset and collation details. This way they get inherited to all newly
created database tables and columns.
In your mapping configuration, the column definition (for example, the
``#[Column]`` attribute) has an ``options`` parameter where you can specify
the ``charset`` and ``collation``. The default values are ``utf8`` and
``utf8_unicode_ci``, respectively.
Entity Classes
--------------
@@ -32,11 +32,12 @@ upon insert:
class User
{
const STATUS_DISABLED = 0;
const STATUS_ENABLED = 1;
private const STATUS_DISABLED = 0;
private const STATUS_ENABLED = 1;
private $algorithm = "sha1";
private $status = self:STATUS_DISABLED;
private string $algorithm = "sha1";
/** @var self::STATUS_* */
private int $status = self::STATUS_DISABLED;
}
.
@@ -52,7 +53,7 @@ or adding entities to a collection twice. You have to check for both conditions
in the code before calling ``$em->flush()`` if you know that unique constraint failures
can occur.
In `Symfony2 <http://www.symfony.com>`_ for example there is a Unique Entity Validator
In `Symfony2 <https://www.symfony.com>`_ for example there is a Unique Entity Validator
to achieve this task.
For collections you can check with ``$collection->contains($entity)`` if an entity is already
@@ -112,8 +113,8 @@ over this collection using a LIMIT statement (or vendor equivalent).
Doctrine does not offer a solution for this out of the box but there are several extensions
that do:
* `DoctrineExtensions <http://github.com/beberlei/DoctrineExtensions>`_
* `Pagerfanta <http://github.com/whiteoctober/pagerfanta>`_
* `DoctrineExtensions <https://github.com/beberlei/DoctrineExtensions>`_
* `Pagerfanta <https://github.com/whiteoctober/pagerfanta>`_
Why does pagination not work correctly with fetch joins?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -28,10 +28,11 @@ table alias of the SQL table of the entity.
In the case of joined or single table inheritance, you always get passed the ClassMetadata of the
inheritance root. This is necessary to avoid edge cases that would break the SQL when applying the filters.
Parameters for the query should be set on the filter object by
``SQLFilter#setParameter()``. Only parameters set via this function can be used
in filters. The ``SQLFilter#getParameter()`` function takes care of the
proper quoting of parameters.
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
2. The filter must be deterministic. Don't change the values base on external inputs.
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
.. code-block:: php
@@ -42,7 +43,7 @@ proper quoting of parameters.
class MyLocaleFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias): string
{
// Check if the entity implements the LocalAware interface
if (!$targetEntity->reflClass->implementsInterface('LocaleAware')) {
@@ -53,6 +54,9 @@ proper quoting of parameters.
}
}
If the parameter is an array and should be quoted as a list of values for an IN query
this is possible with the alternative ``SQLFilter#setParameterList()`` and
``SQLFilter#getParameterList()`` functions.
Configuration
-------------
@@ -89,3 +93,34 @@ object.
want to refresh or reload an object after having modified a filter or the
FilterCollection, then you should clear the EntityManager and re-fetch your
entities, having the new rules for filtering applied.
Suspending/Restoring Filters
----------------------------
When a filter is disabled, the instance is fully deleted and all the filter
parameters previously set are lost. Then, if you enable it again, a new filter
is created without the previous filter parameters. If you want to keep a filter
(in order to use it later) but temporary disable it, you'll need to use the
``FilterCollection#suspend($name)`` and ``FilterCollection#restore($name)``
methods instead.
.. code-block:: php
<?php
$filter = $em->getFilters()->enable("locale");
$filter->setParameter('locale', 'en');
// Temporary suspend the filter
$filter = $em->getFilters()->suspend("locale");
// Do things
// Then restore it, the locale parameter will still be set
$filter = $em->getFilters()->restore("locale");
.. warning::
If you enable a previously disabled filter, doctrine will create a new
one without keeping any of the previously parameter set with
``SQLFilter#setParameter()`` or ``SQLFilter#getParameterList()``. If you
want to restore the previously disabled filter instead, you must use the
``FilterCollection#restore($name)`` method.

View File

@@ -11,7 +11,7 @@ request and can greatly improve performance.
"If you care about performance and don't use a bytecode
cache then you don't really care about performance. Please get one
and start using it."
*Stas Malyshev, Core Contributor to PHP and Zend Employee*
@@ -27,11 +27,13 @@ Doctrine will need to load your mapping information on every single
request and has to parse each DQL query on every single request.
This is a waste of resources.
The preferred cache driver for metadata and query caches is ``PhpFileCache``.
This driver serializes cache items and writes them to a file.
The preferred cache adapter for metadata and query caches is a PHP file
cache like Symfony's
`PHP files adapter <https://symfony.com/doc/current/components/cache/adapters/php_files_adapter.html>`_.
This kind of cache serializes cache items and writes them to a file.
This allows for opcode caching to be used and provides high performance in most scenarios.
See :ref:`integrating-with-the-orm`
See :ref:`types-of-caches`
Alternative Query Result Formats
--------------------------------
@@ -43,13 +45,32 @@ in scenarios where data is loaded for read-only purposes.
Read-Only Entities
------------------
You can mark entities as read only (See metadata mapping
references for details). This means that the entity marked as read only is never considered
for updates, which means when you call flush on the EntityManager these entities are skipped
even if properties changed. Read-Only allows to persist new entities of a kind and remove existing
ones, they are just not considered for updates.
You can mark entities as read only. For details, see :ref:`attrref_entity`
See :ref:`annref_entity`
This means that the entity marked as read only is never considered for updates.
During flush on the EntityManager these entities are skipped even if properties
changed.
Read-Only allows to persist new entities of a kind and remove existing ones,
they are just not considered for updates.
You can also explicitly mark individual entities read only directly on the
UnitOfWork via a call to ``markReadOnly()``:
.. code-block:: php
$user = $entityManager->find(User::class, $id);
$entityManager->getUnitOfWork()->markReadOnly($user);
Or you can set all objects that are the result of a query hydration to be
marked as read only with the following query hint:
.. code-block:: php
$query = $entityManager->createQuery('SELECT u FROM App\\Entity\\User u');
$query->setHint(Query::HINT_READ_ONLY, true);
$users = $query->getResult();
Extra-Lazy Collections
----------------------
@@ -70,9 +91,9 @@ Apply Best Practices
A lot of the points mentioned in the Best Practices chapter will
also positively affect the performance of Doctrine.
See :doc:`Best Practices <reference/best-practices>`
See :doc:`Best Practices </reference/best-practices>`
Change Tracking policies
------------------------
See: :doc:`Change Tracking Policies <reference/change-tracking-policies>`
See: :doc:`Change Tracking Policies <change-tracking-policies>`

View File

@@ -1,6 +1,9 @@
Inheritance Mapping
===================
This chapter explains the available options for mapping class
hierarchies.
Mapped Superclasses
-------------------
@@ -12,49 +15,96 @@ is common to multiple entity classes.
Mapped superclasses, just as regular, non-mapped classes, can
appear in the middle of an otherwise mapped inheritance hierarchy
(through Single Table Inheritance or Class Table Inheritance).
(through Single Table Inheritance or Class Table Inheritance). They
are not query-able, and need not have an ``#[Id]`` property.
No database table will be created for a mapped superclass itself,
only for entity classes inheriting from it. That implies that a
mapped superclass cannot be the ``targetEntity`` in associations.
In other words, a mapped superclass can use unidirectional One-To-One
and Many-To-One associations where it is the owning side.
Many-To-Many associations are only possible if the mapped
superclass is only used in exactly one entity at the moment. For further
support of inheritance, the single or joined table inheritance features
have to be used.
.. note::
A mapped superclass cannot be an entity, it is not query-able and
persistent relationships defined by a mapped superclass must be
unidirectional (with an owning side only). This means that One-To-Many
associations are not possible on a mapped superclass at all.
Furthermore Many-To-Many associations are only possible if the
mapped superclass is only used in exactly one entity at the moment.
For further support of inheritance, the single or
joined table inheritance features have to be used.
One-To-Many associations are not generally possible on a mapped
superclass, since they require the "many" side to hold the foreign
key.
It is, however, possible to use the :doc:`ResolveTargetEntityListener </cookbook/resolve-target-entity-listener>`
to replace references to a mapped superclass with an entity class at runtime.
As long as there is only one entity subclass inheriting from the mapped
superclass and all references to the mapped superclass are resolved to that
entity class at runtime, the mapped superclass *can* use One-To-Many associations
and be named as the ``targetEntity`` on the owning sides.
.. warning::
At least when using attributes or annotations to specify your mapping,
it *seems* as if you could inherit from a base class that is neither
an entity nor a mapped superclass, but has properties with mapping configuration
on them that would also be used in the inheriting class.
This, however, is due to how the corresponding mapping
drivers work and what the PHP reflection API reports for inherited fields.
Such a configuration is explicitly not supported. To give just one example,
it will break for ``private`` properties.
.. note::
You may be tempted to use traits to mix mapped fields or relationships
into your entity classes to circumvent some of the limitations of
mapped superclasses. Before doing that, please read the section on traits
in the :doc:`Limitations and Known Issues </reference/limitations-and-known-issues>` chapter.
Example:
.. code-block:: php
<?php
/** @MappedSuperclass */
class MappedSuperclassBase
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\OneToOne;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\MappedSuperclass;
use Doctrine\ORM\Mapping\Entity;
#[MappedSuperclass]
class Person
{
/** @Column(type="integer") */
protected $mapped1;
/** @Column(type="string") */
protected $mapped2;
/**
* @OneToOne(targetEntity="MappedSuperclassRelated1")
* @JoinColumn(name="related1_id", referencedColumnName="id")
*/
protected $mappedRelated1;
#[Column(type: 'integer')]
protected int $mapped1;
#[Column(type: 'string')]
protected string $mapped2;
#[OneToOne(targetEntity: Toothbrush::class)]
#[JoinColumn(name: 'toothbrush_id', referencedColumnName: 'id')]
protected Toothbrush|null $toothbrush = null;
// ... more fields and methods
}
/** @Entity */
class EntitySubClass extends MappedSuperclassBase
#[Entity]
class Employee extends Person
{
/** @Id @Column(type="integer") */
private $id;
/** @Column(type="string") */
private $name;
#[Id, Column(type: 'integer')]
private int|null $id = null;
#[Column(type: 'string')]
private string $name;
// ... more fields and methods
}
#[Entity]
class Toothbrush
{
#[Id, Column(type: 'integer')]
private int|null $id = null;
// ... more fields and methods
}
@@ -63,31 +113,106 @@ like this (this is for SQLite):
.. code-block:: sql
CREATE TABLE EntitySubClass (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, related1_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
CREATE TABLE Employee (mapped1 INTEGER NOT NULL, mapped2 TEXT NOT NULL, id INTEGER NOT NULL, name TEXT NOT NULL, toothbrush_id INTEGER DEFAULT NULL, PRIMARY KEY(id))
As you can see from this DDL snippet, there is only a single table
for the entity subclass. All the mappings from the mapped
superclass were inherited to the subclass as if they had been
defined on that class directly.
Entity Inheritance
------------------
As soon as one entity class inherits from another entity class, either
directly, with a mapped superclass or other unmapped (also called
"transient") classes in between, these entities form an inheritance
hierarchy. The topmost entity class in this hierarchy is called the
root entity, and the hierarchy includes all entities that are
descendants of this root entity.
On the root entity class, ``#[InheritanceType]``,
``#[DiscriminatorColumn]`` and ``#[DiscriminatorMap]`` must be specified.
``#[InheritanceType]`` specifies one of the two available inheritance
mapping strategies that are explained in the following sections.
``#[DiscriminatorColumn]`` designates the so-called discriminator column.
This is an extra column in the table that keeps information about which
type from the hierarchy applies for a particular database row.
``#[DiscriminatorMap]`` declares the possible values for the discriminator
column and maps them to class names in the hierarchy. This discriminator map
has to declare all non-abstract entity classes that exist in that particular
inheritance hierarchy. That includes the root as well as any intermediate
entity classes, given they are not abstract.
The names of the classes in the discriminator map do not need to be fully
qualified if the classes are contained in the same namespace as the entity
class on which the discriminator map is applied.
If no discriminator map is provided, then the map is generated
automatically. The automatically generated discriminator map contains the
lowercase short name of each class as key.
.. note::
Automatically generating the discriminator map is very expensive
computation-wise. The mapping driver has to provide all classes
for which mapping configuration exists, and those have to be
loaded and checked against the current inheritance hierarchy
to see if they are part of it. The resulting map, however, can be kept
in the metadata cache.
Performance impact on to-one associations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is a general performance consideration when using entity inheritance:
If the target-entity of a many-to-one or one-to-one association is part of
an inheritance hierarchy, it is preferable for performance reasons that it
be a leaf entity (ie. have no subclasses).
Otherwise, the ORM is currently unable to tell beforehand which entity class
will have to be used, and so no appropriate proxy instance can be created.
That means the referred-to entities will *always* be loaded eagerly, which
might even propagate to relationships of these entities (in the case of
self-referencing associations).
Single Table Inheritance
------------------------
`Single Table Inheritance <http://martinfowler.com/eaaCatalog/singleTableInheritance.html>`_
is an inheritance mapping strategy where all classes of a hierarchy
are mapped to a single database table. In order to distinguish
which row represents which type in the hierarchy a so-called
discriminator column is used.
`Single Table Inheritance <https://martinfowler.com/eaaCatalog/singleTableInheritance.html>`_
is an inheritance mapping strategy where all classes of a hierarchy are
mapped to a single database table.
Example:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace MyProject\Model;
#[Entity]
#[InheritanceType('SINGLE_TABLE')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => Person::class, 'employee' => Employee::class])]
class Person
{
// ...
}
#[Entity]
class Employee extends Person
{
// ...
}
.. code-block:: annotation
<?php
namespace MyProject\Model;
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
@@ -98,7 +223,7 @@ Example:
{
// ...
}
/**
* @Entity
*/
@@ -108,7 +233,7 @@ Example:
}
.. code-block:: yaml
MyProject\Model\Person:
type: entity
inheritanceType: SINGLE_TABLE
@@ -118,30 +243,13 @@ Example:
discriminatorMap:
person: Person
employee: Employee
MyProject\Model\Employee:
type: entity
Things to note:
- The @InheritanceType and @DiscriminatorColumn must be specified
on the topmost class that is part of the mapped entity hierarchy.
- The @DiscriminatorMap specifies which values of the
discriminator column identify a row as being of a certain type. In
the case above a value of "person" identifies a row as being of
type ``Person`` and "employee" identifies a row as being of type
``Employee``.
- All entity classes that is part of the mapped entity hierarchy
(including the topmost class) should be specified in the
@DiscriminatorMap. In the case above Person class included.
- The names of the classes in the discriminator map do not need to
be fully qualified if the classes are contained in the same
namespace as the entity class on which the discriminator map is
applied.
- If no discriminator map is provided, then the map is generated
automatically. The automatically generated discriminator map
contains the lowercase short name of each class as key.
In this example, the ``#[DiscriminatorMap]`` specifies that in the
discriminator column, a value of "person" identifies a row as being of type
``Person`` and employee" identifies a row as being of type ``Employee``.
Design-time considerations
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -157,17 +265,10 @@ Performance impact
This strategy is very efficient for querying across all types in
the hierarchy or for specific types. No table joins are required,
only a WHERE clause listing the type identifiers. In particular,
only a ``WHERE`` clause listing the type identifiers. In particular,
relationships involving types that employ this mapping strategy are
very performing.
There is a general performance consideration with Single Table
Inheritance: If the target-entity of a many-to-one or one-to-one
association is an STI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Otherwise Doctrine *CANNOT* create proxy instances
of this entity and will *ALWAYS* load the entity eagerly.
SQL Schema considerations
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -175,20 +276,21 @@ For Single-Table-Inheritance to work in scenarios where you are
using either a legacy database schema or a self-written database
schema you have to make sure that all columns that are not in the
root entity but in any of the different sub-entities has to allow
null values. Columns that have NOT NULL constraints have to be on
null values. Columns that have ``NOT NULL`` constraints have to be on
the root entity of the single-table inheritance hierarchy.
Class Table Inheritance
-----------------------
`Class Table Inheritance <http://martinfowler.com/eaaCatalog/classTableInheritance.html>`_
`Class Table Inheritance <https://martinfowler.com/eaaCatalog/classTableInheritance.html>`_
is an inheritance mapping strategy where each class in a hierarchy
is mapped to several tables: its own table and the tables of all
parent classes. The table of a child class is linked to the table
of a parent class through a foreign key constraint. Doctrine ORM
implements this strategy through the use of a discriminator column
in the topmost table of the hierarchy because this is the easiest
way to achieve polymorphic queries with Class Table Inheritance.
of a parent class through a foreign key constraint.
The discriminator column is placed in the topmost table of the hierarchy,
because this is the easiest way to achieve polymorphic queries with Class
Table Inheritance.
Example:
@@ -196,42 +298,25 @@ Example:
<?php
namespace MyProject\Model;
/**
* @Entity
* @InheritanceType("JOINED")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "Person", "employee" = "Employee"})
*/
#[Entity]
#[InheritanceType('JOINED')]
#[DiscriminatorColumn(name: 'discr', type: 'string')]
#[DiscriminatorMap(['person' => Person::class, 'employee' => Employee::class])]
class Person
{
// ...
}
/** @Entity */
#[Entity]
class Employee extends Person
{
// ...
}
Things to note:
- The @InheritanceType, @DiscriminatorColumn and @DiscriminatorMap
must be specified on the topmost class that is part of the mapped
entity hierarchy.
- The @DiscriminatorMap specifies which values of the
discriminator column identify a row as being of which type. In the
case above a value of "person" identifies a row as being of type
``Person`` and "employee" identifies a row as being of type
``Employee``.
- The names of the classes in the discriminator map do not need to
be fully qualified if the classes are contained in the same
namespace as the entity class on which the discriminator map is
applied.
- If no discriminator map is provided, then the map is generated
automatically. The automatically generated discriminator map
contains the lowercase short name of each class as key.
As before, the ``#[DiscriminatorMap]`` specifies that in the
discriminator column, a value of "person" identifies a row as being of type
``Person`` and "employee" identifies a row as being of type ``Employee``.
.. note::
@@ -262,17 +347,13 @@ perform just about any query which can have a negative impact on
performance, especially with large tables and/or large hierarchies.
When partial objects are allowed, either globally or on the
specific query, then querying for any type will not cause the
tables of subtypes to be OUTER JOINed which can increase
tables of subtypes to be ``OUTER JOIN``ed which can increase
performance but the resulting partial objects will not fully load
themselves on access of any subtype fields, so accessing fields of
subtypes after such a query is not safe.
There is a general performance consideration with Class Table
Inheritance: If the target-entity of a many-to-one or one-to-one
association is a CTI entity, it is preferable for performance reasons that it
be a leaf entity in the inheritance hierarchy, (ie. have no subclasses).
Otherwise Doctrine *CANNOT* create proxy instances
of this entity and will *ALWAYS* load the entity eagerly.
There is also another important performance consideration that it is *not possible*
to query for the base entity without any ``LEFT JOIN``s to the sub-types.
SQL Schema considerations
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -290,14 +371,16 @@ column and cascading on delete.
Overrides
---------
Used to override a mapping for an entity field or relationship. Can only be
applied to an entity that extends a mapped superclass or uses a trait to
override a relationship or field mapping defined by the mapped superclass or
trait.
Overrides can only be applied to entities that extend a mapped superclass or
use traits. They are used to override a mapping for an entity field or
relationship defined in that mapped superclass or trait.
It is not possible to override attributes or associations in entity to entity
inheritance scenarios, because this can cause unforseen edge case behavior and
increases complexity in ORM internal classes.
It is not supported to use overrides in entity inheritance scenarios.
.. note::
When using traits, make sure not to miss the warnings given in the
:doc:`Limitations and Known Issues</reference/limitations-and-known-issues>` chapter.
Association Override
@@ -311,7 +394,52 @@ Example:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
// user mapping
namespace MyProject\Model;
#[MappedSuperclass]
class User
{
// other fields mapping
/** @var Collection<int, Group> */
#[JoinTable(name: 'users_groups')]
#[JoinColumn(name: 'user_id', referencedColumnName: 'id')]
#[InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
#[ManyToMany(targetEntity: 'Group', inversedBy: 'users')]
protected Collection $groups;
#[ManyToOne(targetEntity: 'Address')]
#[JoinColumn(name: 'address_id', referencedColumnName: 'id')]
protected Address|null $address = null;
}
// admin mapping
namespace MyProject\Model;
#[Entity]
#[AssociationOverrides([
new AssociationOverride(
name: 'groups',
joinTable: new JoinTable(
name: 'users_admingroups',
),
joinColumns: [new JoinColumn(name: 'adminuser_id')],
inverseJoinColumns: [new JoinColumn(name: 'admingroup_id')]
),
new AssociationOverride(
name: 'address',
joinColumns: [new JoinColumn(name: 'adminaddress_id', referencedColumnName: 'id')]
)
])]
class Admin extends User
{
}
.. code-block:: annotation
<?php
// user mapping
@@ -321,7 +449,7 @@ Example:
*/
class User
{
//other fields mapping
// other fields mapping
/**
* @ManyToMany(targetEntity="Group", inversedBy="users")
@@ -329,14 +457,15 @@ Example:
* joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
* )
* @var Collection<int, Group>
*/
protected $groups;
protected Collection $groups;
/**
* @ManyToOne(targetEntity="Address")
* @JoinColumn(name="address_id", referencedColumnName="id")
*/
protected $address;
protected Address|null $address = null;
}
// admin mapping
@@ -456,11 +585,12 @@ Example:
Things to note:
- The "association override" specifies the overrides base on the property name.
- This feature is available for all kind of associations. (OneToOne, OneToMany, ManyToOne, ManyToMany)
- The association type *CANNOT* be changed.
- The override could redefine the joinTables or joinColumns depending on the association type.
- The override could redefine inversedBy to reference more than one extended entity.
- The "association override" specifies the overrides based on the property
name.
- This feature is available for all kind of associations (OneToOne, OneToMany, ManyToOne, ManyToMany).
- The association type *cannot* be changed.
- The override could redefine the ``joinTables`` or ``joinColumns`` depending on the association type.
- The override could redefine ``inversedBy`` to reference more than one extended entity.
- The override could redefine fetch to modify the fetch strategy of the extended entity.
Attribute Override
@@ -471,7 +601,51 @@ Could be used by an entity that extends a mapped superclass to override a field
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
// user mapping
namespace MyProject\Model;
#[MappedSuperclass]
class User
{
#[Id, GeneratedValue, Column(type: 'integer', name: 'user_id', length: 150)]
protected int|null $id = null;
#[Column(name: 'user_name', nullable: true, unique: false, length: 250)]
protected string $name;
// other fields mapping
}
// guest mapping
namespace MyProject\Model;
#[Entity]
#[AttributeOverrides([
new AttributeOverride(
name: 'id',
column: new Column(
name: 'guest_id',
type: 'integer',
length: 140
)
),
new AttributeOverride(
name: 'name',
column: new Column(
name: 'guest_name',
nullable: false,
unique: true,
length: 240
)
)
])]
class Guest extends User
{
}
.. code-block:: annotation
<?php
// user mapping
@@ -482,10 +656,10 @@ Could be used by an entity that extends a mapped superclass to override a field
class User
{
/** @Id @GeneratedValue @Column(type="integer", name="user_id", length=150) */
protected $id;
protected int|null $id = null;
/** @Column(name="user_name", nullable=true, unique=false, length=250) */
protected $name;
protected string $name;
// other fields mapping
}
@@ -588,8 +762,8 @@ Could be used by an entity that extends a mapped superclass to override a field
Things to note:
- The "attribute override" specifies the overrides base on the property name.
- The column type *CANNOT* be changed. If the column type is not equal you get a ``MappingException``
- The "attribute override" specifies the overrides based on the property name.
- The column type *cannot* be changed. If the column type is not equal, you get a ``MappingException``.
- The override can redefine all the attributes except the type.
Query the Type

View File

@@ -1,4 +1,4 @@
Installation
============
The installation chapter has moved to :doc:`Installation and Configuration <reference/configuration>`_.
The installation chapter has moved to :doc:`Installation and Configuration </reference/configuration>`.

View File

@@ -112,10 +112,10 @@ in the core library. We don't think behaviors add more value than
they cost pain and debugging hell. Please see the many different
blog posts we have written on this topics:
- `Doctrine2 "Behaviors" in a Nutshell <http://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html>`_
- `A re-usable Versionable behavior for Doctrine2 <http://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html>`_
- `Write your own ORM on top of Doctrine2 <http://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html>`_
- `Doctrine ORM Behavioral Extensions <http://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
- `Doctrine2 "Behaviors" in a Nutshell <https://www.doctrine-project.org/2010/02/17/doctrine2-behaviours-nutshell.html>`_
- `A re-usable Versionable behavior for Doctrine2 <https://www.doctrine-project.org/2010/02/24/doctrine2-versionable.html>`_
- `Write your own ORM on top of Doctrine2 <https://www.doctrine-project.org/2010/07/19/your-own-orm-doctrine2.html>`_
- `Doctrine ORM Behavioral Extensions <https://www.doctrine-project.org/2010/11/18/doctrine2-behavioral-extensions.html>`_
Doctrine ORM has enough hooks and extension points so that **you** can
add whatever you want on top of it. None of this will ever become
@@ -130,9 +130,50 @@ included in the core of Doctrine ORM. However there are already two
extensions out there that offer support for Nested Set with
ORM:
- `Doctrine2 Hierarchical-Structural Behavior <https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
- `Doctrine2 NestedSet <https://github.com/blt04/doctrine2-nestedset>`_
- `Doctrine2 Hierarchical-Structural Behavior <http://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior>`_
- `Doctrine2 NestedSet <http://github.com/blt04/doctrine2-nestedset>`_
Using Traits in Entity Classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The use of traits in entity or mapped superclasses, at least when they
include mapping configuration or mapped fields, is currently not
endorsed by the Doctrine project. The reasons for this are as follows.
Traits were added in PHP 5.4 more than 10 years ago, but at the same time
more than two years after the initial Doctrine 2 release and the time where
core components were designed.
In fact, this documentation mentions traits only in the context of
:doc:`overriding field association mappings in subclasses </tutorials/override-field-association-mappings-in-subclasses>`.
Coverage of traits in test cases is practically nonexistent.
Thus, you should at least be aware that when using traits in your entity and
mapped superclasses, you will be in uncharted terrain.
.. warning::
There be dragons.
From a more technical point of view, traits basically work at the language level
as if the code contained in them had been copied into the class where the trait
is used, and even private fields are accessible by the using class. In addition to
that, some precedence and conflict resolution rules apply.
When it comes to loading mapping configuration, the annotation and attribute drivers
rely on PHP reflection to inspect class properties including their docblocks.
As long as the results are consistent with what a solution *without* traits would
have produced, this is probably fine.
However, to mention known limitations, it is currently not possible to use "class"
level `annotations <https://github.com/doctrine/orm/pull/1517>`_ or
`attributes <https://github.com/doctrine/orm/issues/8868>`_ on traits, and attempts to
improve parser support for traits as `here <https://github.com/doctrine/annotations/pull/102>`_
or `there <https://github.com/doctrine/annotations/pull/63>`_ have been abandoned
due to complexity.
XML mapping configuration probably needs to completely re-configure or otherwise
copy-and-paste configuration for fields used from traits.
Known Issues
------------
@@ -177,27 +218,3 @@ MySQL with MyISAM tables
Doctrine cannot provide atomic operations when calling ``EntityManager#flush()`` if one
of the tables involved uses the storage engine MyISAM. You must use InnoDB or
other storage engines that support transactions if you need integrity.
Entities, Proxies and Reflection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using methods for Reflection on entities can be prone to error, when the entity
is actually a proxy the following methods will not work correctly:
- ``new ReflectionClass``
- ``new ReflectionObject``
- ``get_class()``
- ``get_parent_class()``
This is why ``Doctrine\Common\Util\ClassUtils`` class exists that has similar
methods, which resolve the proxy problem beforehand.
.. code-block:: php
<?php
use Doctrine\Common\Util\ClassUtils;
$bookProxy = $entityManager->getReference('Acme\Book');
$reflection = ClassUtils::newReflectionClass($bookProxy);
$class = ClassUtils::getClass($bookProxy)¸

View File

@@ -13,9 +13,15 @@ metadata:
- **XML files** (XmlDriver)
- **Attributes** (AttributeDriver)
- **PHP Code in files or static functions** (PhpDriver)
There are also two deprecated ways to do this:
- **Class DocBlock Annotations** (AnnotationDriver)
- **YAML files** (YamlDriver)
- **PHP Code in files or static functions** (PhpDriver)
They will be removed in 3.0, make sure to avoid them.
Something important to note about the above drivers is they are all
an intermediate step to the same end result. The mapping
@@ -38,8 +44,10 @@ an entity.
$em->getConfiguration()->setMetadataCacheImpl(new ApcuCache());
If you want to use one of the included core metadata drivers you
just need to configure it. All the drivers are in the
If you want to use one of the included core metadata drivers you need to
configure it. If you pick the annotation driver despite it being
deprecated, you will additionally need to install
``doctrine/annotations``. All the drivers are in the
``Doctrine\ORM\Mapping\Driver`` namespace:
.. code-block:: php
@@ -53,69 +61,84 @@ Implementing Metadata Drivers
In addition to the included metadata drivers you can very easily
implement your own. All you need to do is define a class which
implements the ``Driver`` interface:
implements the ``MappingDriver`` interface:
.. code-block:: php
<?php
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
interface Driver
declare(strict_types=1);
namespace Doctrine\Persistence\Mapping\Driver;
use Doctrine\Persistence\Mapping\ClassMetadata;
/**
* Contract for metadata drivers.
*/
interface MappingDriver
{
/**
* Loads the metadata for the specified class into the provided container.
*
* @param string $className
* @param ClassMetadataInfo $metadata
*
* @psalm-param class-string<T> $className
* @psalm-param ClassMetadata<T> $metadata
*
* @return void
*
* @template T of object
*/
function loadMetadataForClass($className, ClassMetadataInfo $metadata);
public function loadMetadataForClass(string $className, ClassMetadata $metadata);
/**
* Gets the names of all mapped classes known to this driver.
*
* @return array The names of all mapped classes known to this driver.
*/
function getAllClassNames();
/**
* Whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a
* MappedSuperclass.
*
* @param string $className
* @return boolean
* @return array<int, string> The names of all mapped classes known to this driver.
* @psalm-return list<class-string>
*/
function isTransient($className);
public function getAllClassNames();
/**
* Returns whether the class with the specified name should have its metadata loaded.
* This is only the case if it is either mapped as an Entity or a MappedSuperclass.
*
* @psalm-param class-string $className
*
* @return bool
*/
public function isTransient(string $className);
}
If you want to write a metadata driver to parse information from
some file format we've made your life a little easier by providing
the ``AbstractFileDriver`` implementation for you to extend from:
the ``FileDriver`` implementation for you to extend from:
.. code-block:: php
<?php
class MyMetadataDriver extends AbstractFileDriver
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\Mapping\Driver\FileDriver;
class MyMetadataDriver extends FileDriver
{
/**
* {@inheritdoc}
* {@inheritDoc}
*/
protected $_fileExtension = '.dcm.ext';
/**
* {@inheritdoc}
* {@inheritDoc}
*/
public function loadMetadataForClass($className, ClassMetadataInfo $metadata)
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
$data = $this->_loadMappingFile($file);
// populate ClassMetadataInfo instance from $data
// populate ClassMetadata instance from $data
}
/**
* {@inheritdoc}
* {@inheritDoc}
*/
protected function _loadMappingFile($file)
{
@@ -125,13 +148,12 @@ the ``AbstractFileDriver`` implementation for you to extend from:
.. note::
When using the ``AbstractFileDriver`` it requires that you
only have one entity defined per file and the file named after the
class described inside where namespace separators are replaced by
periods. So if you have an entity named ``Entities\User`` and you
wanted to write a mapping file for your driver above you would need
to name the file ``Entities.User.dcm.ext`` for it to be
recognized.
When using the ``FileDriver`` it requires that you only have one
entity defined per file and the file named after the class described
inside where namespace separators are replaced by periods. So if you
have an entity named ``Entities\User`` and you wanted to write a
mapping file for your driver above you would need to name the file
``Entities.User.dcm.ext`` for it to be recognized.
Now you can use your ``MyMetadataDriver`` implementation by setting
@@ -154,14 +176,6 @@ entity when needed.
You have all the methods you need to manually specify the mapping
information instead of using some mapping file to populate it from.
The base ``ClassMetadataInfo`` class is responsible for only data
storage and is not meant for runtime use. It does not require that
the class actually exists yet so it is useful for describing some
entity before it exists and using that information to generate for
example the entities themselves. The class ``ClassMetadata``
extends ``ClassMetadataInfo`` and adds some functionality required
for runtime usage and requires that the PHP class is present and
can be autoloaded.
You can read more about the API of the ``ClassMetadata`` classes in
the PHP Mapping chapter.
@@ -190,5 +204,3 @@ iterate over them:
foreach ($class->fieldMappings as $fieldMapping) {
echo $fieldMapping['fieldName'] . "\n";
}

View File

@@ -7,7 +7,7 @@ reduce the verbosity of the mapping document, eliminating repetitive noise (eg:
.. warning
The naming strategy is always overridden by entity mapping such as the `Table` annotation.
The naming strategy is always overridden by entity mapping such as the `Table` attribute.
Configuring a naming strategy
-----------------------------

View File

@@ -71,7 +71,7 @@ with inheritance hierarchies.
use Doctrine\ORM\Query\ResultSetMappingBuilder;
$sql = "SELECT u.id, u.name, a.id AS address_id, a.street, a.city " .
$sql = "SELECT u.id, u.name, a.id AS address_id, a.street, a.city " .
"FROM users u INNER JOIN address a ON u.address_id = a.id";
$rsm = new ResultSetMappingBuilder($entityManager);
@@ -250,6 +250,40 @@ The first parameter is the name of the column in the SQL result set
and the second parameter is the result alias under which the value
of the column will be placed in the transformed Doctrine result.
Special case: DTOs
...................
You can also use ``ResultSetMapping`` to map the results of a native SQL
query to a DTO (Data Transfer Object). This is done by adding scalar
results for each argument of the DTO's constructor, then filling the
``newObjectMappings`` property of the ``ResultSetMapping`` with
information about where to map each scalar result:
.. code-block:: php
<?php
$rsm = new ResultSetMapping();
$rsm->addScalarResult('name', 1, 'string');
$rsm->addScalarResult('email', 2, 'string');
$rsm->addScalarResult('city', 3, 'string');
$rsm->newObjectMappings['name'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0, // a result can contain many DTOs, this is the index of the DTO to map to
'argIndex' => 0, // each scalar result can be mapped to a different argument of the DTO constructor
];
$rsm->newObjectMappings['email'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 1,
];
$rsm->newObjectMappings['city'] = [
'className' => CmsUserDTO::class,
'objIndex' => 0,
'argIndex' => 2,
];
Meta results
~~~~~~~~~~~~
@@ -265,7 +299,7 @@ detail:
<?php
/**
* Adds a meta column (foreign key or discriminator column) to the result set.
*
*
* @param string $alias
* @param string $columnAlias
* @param string $columnName
@@ -320,10 +354,10 @@ entity.
$rsm->addEntityResult('User', 'u');
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'name', 'name');
$query = $this->_em->createNativeQuery('SELECT id, name FROM users WHERE name = ?', $rsm);
$query->setParameter(1, 'romanb');
$users = $query->getResult();
The result would look like this:
@@ -356,10 +390,10 @@ thus owns the foreign key.
$rsm->addFieldResult('u', 'id', 'id');
$rsm->addFieldResult('u', 'name', 'name');
$rsm->addMetaResult('u', 'address_id', 'address_id');
$query = $this->_em->createNativeQuery('SELECT id, name, address_id FROM users WHERE name = ?', $rsm);
$query->setParameter(1, 'romanb');
$users = $query->getResult();
Foreign keys are used by Doctrine for lazy-loading purposes when
@@ -385,12 +419,12 @@ associations that are lazy.
$rsm->addFieldResult('a', 'address_id', 'id');
$rsm->addFieldResult('a', 'street', 'street');
$rsm->addFieldResult('a', 'city', 'city');
$sql = 'SELECT u.id, u.name, a.id AS address_id, a.street, a.city FROM users u ' .
'INNER JOIN address a ON u.address_id = a.id WHERE u.name = ?';
$query = $this->_em->createNativeQuery($sql, $rsm);
$query->setParameter(1, 'romanb');
$users = $query->getResult();
In this case the nested entity ``Address`` is registered with the
@@ -420,10 +454,10 @@ to map the hierarchy (both use a discriminator column).
$rsm->addFieldResult('u', 'name', 'name');
$rsm->addMetaResult('u', 'discr', 'discr'); // discriminator column
$rsm->setDiscriminatorColumn('u', 'discr');
$query = $this->_em->createNativeQuery('SELECT id, name, discr FROM users WHERE name = ?', $rsm);
$query->setParameter(1, 'romanb');
$users = $query->getResult();
Note that in the case of Class Table Inheritance, an example as
@@ -435,6 +469,10 @@ strategy but with native SQL it is your responsibility.
Named Native Query
------------------
.. note::
Named Native Queries are deprecated as of version 2.9 and will be removed in ORM 3.0
You can also map a native query using a named native query mapping.
To achieve that, you must describe the SQL resultset structure
@@ -789,7 +827,7 @@ followed by a dot ("."), followed by the name or the field or property of the pr
6:
name: address.country
column: a_country
If you retrieve a single entity and if you use the default mapping,

View File

@@ -1,6 +1,14 @@
Partial Objects
===============
.. note::
Creating Partial Objects through DQL is deprecated and
will be removed in the future, use data transfer object
support in DQL instead. (\ `Details
<https://github.com/doctrine/orm/issues/8471>`_)
A partial object is an object whose state is not fully initialized
after being reconstituted from the database and that is
disconnected from the rest of its data. The following section will

View File

@@ -9,6 +9,11 @@ the code in PHP files or inside of a static function named
PHP Files
---------
.. note::
PHPDriver is deprecated and will be removed in 3.0, use StaticPHPDriver
instead.
If you wish to write your mapping information inside PHP files that
are named after the entity and included to populate the metadata
for an entity you can do so by using the ``PHPDriver``:
@@ -85,12 +90,14 @@ Static Function
In addition to the PHP files you can also specify your mapping
information inside of a static function defined on the entity class
itself. This is useful for cases where you want to keep your entity
and mapping information together but don't want to use annotations.
For this you just need to use the ``StaticPHPDriver``:
and mapping information together but don't want to use attributes or
annotations. For this you just need to use the ``StaticPHPDriver``:
.. code-block:: php
<?php
use Doctrine\Persistence\Mapping\Driver\StaticPHPDriver;
$driver = new StaticPHPDriver('/path/to/entities');
$em->getConfiguration()->setMetadataDriverImpl($driver);
@@ -160,7 +167,7 @@ The API of the ClassMetadataBuilder has the following methods with a fluent inte
- ``addNamedQuery($name, $dqlQuery)``
- ``setJoinedTableInheritance()``
- ``setSingleTableInheritance()``
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255)``
- ``setDiscriminatorColumn($name, $type = 'string', $length = 255, $columnDefinition = null, $enumType = null, $options = [])``
- ``addDiscriminatorMapClass($name, $class)``
- ``setChangeTrackingPolicyDeferredExplicit()``
- ``setChangeTrackingPolicyNotify()``
@@ -180,13 +187,12 @@ It also has several methods that create builders (which are necessary for advanc
- ``createManyToMany($name, $targetEntity)`` returns an ``ManyToManyAssociationBuilder`` instance
- ``createOneToMany($name, $targetEntity)`` returns an ``OneToManyAssociationBuilder`` instance
ClassMetadataInfo API
---------------------
ClassMetadata API
-----------------
The ``ClassMetadataInfo`` class is the base data object for storing
the mapping metadata for a single entity. It contains all the
getters and setters you need populate and retrieve information for
an entity.
The ``ClassMetadata`` class is the data object for storing the mapping
metadata for a single entity. It contains all the getters and setters
you need populate and retrieve information for an entity.
General Setters
~~~~~~~~~~~~~~~
@@ -304,13 +310,11 @@ Lifecycle Callback Getters
- ``hasLifecycleCallbacks($lifecycleEvent)``
- ``getLifecycleCallbacks($event)``
ClassMetadata API
-----------------
Runtime reflection methods
~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``ClassMetadata`` class extends ``ClassMetadataInfo`` and adds
the runtime functionality required by Doctrine. It adds a few extra
methods related to runtime reflection for working with the entities
themselves.
These are methods related to runtime reflection for working with the
entities themselves.
- ``getReflectionClass()``
@@ -321,5 +325,3 @@ themselves.
- ``setIdentifierValues($entity, $id)``
- ``setFieldValue($entity, $field, $value)``
- ``getFieldValue($entity, $field)``

View File

@@ -13,7 +13,7 @@ as you want, or just pick a preferred one.
The ``QueryBuilder`` is not an abstraction of DQL, but merely a tool to dynamically build it.
You should still use plain DQL when you can, as it is simpler and more readable.
More about this in the :doc:`FAQ <faq>`_.
More about this in the :doc:`FAQ <faq>`.
Constructing a new QueryBuilder object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -252,8 +252,8 @@ while the named placeholders start with a : followed by a string.
Calling ``setParameter()`` automatically infers which type you are setting as
value. This works for integers, arrays of strings/integers, DateTime instances
and for managed entities. If you want to set a type explicitly you can call
the third argument to ``setParameter()`` explicitly. It accepts either a PDO
type or a DBAL Type name for conversion.
the third argument to ``setParameter()`` explicitly. It accepts either a DBAL
Doctrine\DBAL\ParameterType::* or a DBAL Type name for conversion.
.. note::
@@ -268,7 +268,7 @@ type or a DBAL Type name for conversion.
use Doctrine\DBAL\Types\Types;
// prevents attempt to load metadata for date time class, improving performance
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATE_IMMUTABLE)
$qb->setParameter('date', new \DateTimeImmutable(), Types::DATETIME_IMMUTABLE)
If you've got several parameters to bind to your query, you can
also use setParameters() instead of setParameter() with the
@@ -277,10 +277,17 @@ following syntax:
.. code-block:: php
<?php
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query\Parameter;
// $qb instanceof QueryBuilder
// Query here...
$qb->setParameters(array(1 => 'value for ?1', 2 => 'value for ?2'));
$qb->setParameters(new ArrayCollection([
new Parameter('1', 'value for ?1'),
new Parameter('2', 'value for ?2')
]));
Getting already bound parameters is easy - simply use the above
mentioned syntax with "getParameter()" or "getParameters()":
@@ -427,6 +434,12 @@ complete list of supported helper methods available:
// Example - $qb->expr()->isNotNull('u.id') => u.id IS NOT NULL
public function isNotNull($x); // Returns string
// Example - $qb->expr()->isMemberOf('?1', 'u.groups') => ?1 MEMBER OF u.groups
public function isMemberOf($x, $y); // Returns Expr\Comparison instance
// Example - $qb->expr()->isInstanceOf('u', Employee::class) => u INSTANCE OF Employee
public function isInstanceOf($x, $y); // Returns Expr\Comparison instance
/** Arithmetic objects **/
@@ -513,6 +526,9 @@ complete list of supported helper methods available:
// Example - $qb->expr()->sqrt('u.currentBalance')
public function sqrt($x); // Returns Expr\Func
// Example - $qb->expr()->mod('u.currentBalance', '10')
public function mod($x); // Returns Expr\Func
// Example - $qb->expr()->count('u.firstname')
public function count($x); // Returns Expr\Func
@@ -533,7 +549,7 @@ using ``addCriteria``:
// ...
$criteria = Criteria::create()
->orderBy(['firstName', 'ASC']);
->orderBy(['firstName' => Criteria::ASC]);
// $qb instanceof QueryBuilder
$qb->addCriteria($criteria);
@@ -562,8 +578,6 @@ of DQL. It takes 3 parameters: ``$dqlPartName``, ``$dqlPart`` and
not (no effect on the ``where`` and ``having`` DQL query parts,
which always override all previously defined items)
-
.. code-block:: php
<?php

View File

@@ -31,31 +31,31 @@ Each cache region resides in a specific cache namespace and has its own lifetime
Notice that when caching collection and queries only identifiers are stored.
The entity values will be stored in its own region
Something like below for an entity region :
Something like below for an entity region:
.. code-block:: php
<?php
[
'region_name:entity_1_hash' => ['id'=> 1, 'name' => 'FooBar', 'associationName'=>null],
'region_name:entity_2_hash' => ['id'=> 2, 'name' => 'Foo', 'associationName'=>['id'=>11]],
'region_name:entity_3_hash' => ['id'=> 3, 'name' => 'Bar', 'associationName'=>['id'=>22]]
'region_name:entity_1_hash' => ['id' => 1, 'name' => 'FooBar', 'associationName' => null],
'region_name:entity_2_hash' => ['id' => 2, 'name' => 'Foo', 'associationName' => ['id' => 11]],
'region_name:entity_3_hash' => ['id' => 3, 'name' => 'Bar', 'associationName' => ['id' => 22]]
];
If the entity holds a collection that also needs to be cached.
An collection region could look something like :
An collection region could look something like:
.. code-block:: php
<?php
[
'region_name:entity_1_coll_assoc_name_hash' => ['ownerId'=> 1, 'list' => [1, 2, 3]],
'region_name:entity_2_coll_assoc_name_hash' => ['ownerId'=> 2, 'list' => [2, 3]],
'region_name:entity_3_coll_assoc_name_hash' => ['ownerId'=> 3, 'list' => [2, 4]]
'region_name:entity_1_coll_assoc_name_hash' => ['ownerId' => 1, 'list' => [1, 2, 3]],
'region_name:entity_2_coll_assoc_name_hash' => ['ownerId' => 2, 'list' => [2, 3]],
'region_name:entity_3_coll_assoc_name_hash' => ['ownerId' => 3, 'list' => [2, 4]]
];
A query region might be something like :
A query region might be something like:
.. code-block:: php
@@ -93,8 +93,6 @@ Cache region
``Doctrine\ORM\Cache\Region`` defines a contract for accessing a particular
cache region.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Region.html>`_.
Concurrent cache region
~~~~~~~~~~~~~~~~~~~~~~~
@@ -105,8 +103,6 @@ If you want to use an ``READ_WRITE`` cache, you should consider providing your o
``Doctrine\ORM\Cache\ConcurrentRegion`` defines a contract for concurrently managed data region.
`See API Doc <https://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/ConcurrentRegion.html>`_.
Timestamp region
~~~~~~~~~~~~~~~~
@@ -114,8 +110,6 @@ Timestamp region
Tracks the timestamps of the most recent updates to particular entity.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/TimestampRegion.html>`_.
.. _reference-second-level-cache-mode:
Caching mode
@@ -132,7 +126,7 @@ Caching mode
* Read Write Cache doesnt employ any locks but can do reads, inserts, updates and deletes.
* Good if the application needs to update data rarely.
* ``READ_WRITE``
@@ -147,21 +141,21 @@ Built-in cached persisters
Cached persisters are responsible to access cache regions.
+-----------------------+-------------------------------------------------------------------------------------------+
| Cache Usage | Persister |
+=======================+===========================================================================================+
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadOnlyCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\ReadWriteCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Entity\\NonStrictReadWriteCachedEntityPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
| READ_ONLY | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadOnlyCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
| READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\ReadWriteCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | Doctrine\\ORM\\Cache\\Persister\\Collection\\NonStrictReadWriteCachedCollectionPersister |
+-----------------------+-------------------------------------------------------------------------------------------+
+-----------------------+------------------------------------------------------------------------------------------+
| Cache Usage | Persister |
+=======================+==========================================================================================+
| READ_ONLY | ``Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
| READ_WRITE | ``Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | ``Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
| READ_ONLY | ``Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
| READ_WRITE | ``Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
| NONSTRICT_READ_WRITE | ``Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister`` |
+-----------------------+------------------------------------------------------------------------------------------+
Configuration
-------------
@@ -172,15 +166,16 @@ Enable Second Level Cache
~~~~~~~~~~~~~~~~~~~~~~~~~
To enable the second-level-cache, you should provide a cache factory.
``\Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
``Doctrine\ORM\Cache\DefaultCacheFactory`` is the default implementation.
.. code-block:: php
<?php
/* @var $config \Doctrine\ORM\Cache\RegionsConfiguration */
/* @var $cache \Doctrine\Common\Cache\Cache */
/** @var \Doctrine\ORM\Cache\RegionsConfiguration $cacheConfig */
/** @var \Psr\Cache\CacheItemPoolInterface $cache */
/** @var \Doctrine\ORM\Configuration $config */
$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($config, $cache);
$factory = new \Doctrine\ORM\Cache\DefaultCacheFactory($cacheConfig, $cache);
// Enable second-level-cache
$config->setSecondLevelCacheEnabled();
@@ -195,7 +190,7 @@ Cache Factory
Cache Factory is the main point of extension.
It allows you to provide a specific implementation of the following components :
It allows you to provide a specific implementation of the following components:
``QueryCache``
stores and retrieves query cache results.
@@ -208,8 +203,6 @@ It allows you to provide a specific implementation of the following components :
``CollectionHydrator``
transforms collections into cache entries and cache entries into collections
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/DefaultCacheFactory.html>`_.
Region Lifetime
~~~~~~~~~~~~~~~
@@ -218,8 +211,9 @@ To specify a default lifetime for all regions or specify a different lifetime fo
.. code-block:: php
<?php
/* @var $config \Doctrine\ORM\Configuration */
/* @var $cacheConfig \Doctrine\ORM\Cache\CacheConfiguration */
/** @var \Doctrine\ORM\Configuration $config */
/** @var \Doctrine\ORM\Cache\CacheConfiguration $cacheConfig */
/** @var \Doctrine\ORM\Cache\RegionsConfiguration $regionConfig */
$cacheConfig = $config->getSecondLevelCacheConfiguration();
$regionConfig = $cacheConfig->getRegionsConfiguration();
@@ -232,12 +226,12 @@ Cache Log
~~~~~~~~~
By providing a cache logger you should be able to get information about all cache operations such as hits, misses and puts.
``\Doctrine\ORM\Cache\Logging\StatisticsCacheLogger`` is a built-in implementation that provides basic statistics.
``Doctrine\ORM\Cache\Logging\StatisticsCacheLogger`` is a built-in implementation that provides basic statistics.
.. code-block:: php
<?php
/* @var $config \Doctrine\ORM\Configuration */
/** @var \Doctrine\ORM\Configuration $config */
$logger = new \Doctrine\ORM\Cache\Logging\StatisticsCacheLogger();
// Cache logger
@@ -267,12 +261,9 @@ By providing a cache logger you should be able to get information about all cach
$logger->getMissCount();
If you want to get more information you should implement
``\Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
``Doctrine\ORM\Cache\Logging\CacheLogger`` and collect
all the information you want.
`See API Doc <http://www.doctrine-project.org/api/orm/current/Doctrine/ORM/Cache/Logging/CacheLogger.html>`_.
Entity cache definition
-----------------------
* Entity cache configuration allows you to define the caching strategy and region for an entity.
@@ -286,26 +277,44 @@ level cache region.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
#[Cache(usage: 'READ_ONLY', region: 'my_entity_region')]
class Country
{
#[Id]
#[GeneratedValue]
#[Column]
protected int|null $id = null;
#[Column(unique: true)]
protected string $name;
// other properties and methods
}
.. code-block:: annotation
<?php
/**
* @Entity
* @Cache(usage="READ_ONLY", region="my_entity_region")
* @Cache("NONSTRICT_READ_WRITE")
*/
class Country
class State
{
/**
* @Id
* @GeneratedValue
* @Column(type="integer")
*/
protected $id;
protected int|null $id = null;
/**
* @Column(unique=true)
*/
protected $name;
protected string $name;
// other properties and methods
}
@@ -313,7 +322,10 @@ level cache region.
.. code-block:: xml
<?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">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://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="Country">
<cache usage="READ_ONLY" region="my_entity_region" />
<id name="id" type="integer" column="id">
@@ -328,8 +340,8 @@ level cache region.
Country:
type: entity
cache:
usage : READ_ONLY
region : my_entity_region
usage: READ_ONLY
region: my_entity_region
id:
id:
type: integer
@@ -349,7 +361,35 @@ It caches the primary keys of association and cache each element will be cached
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
#[Cache(usage: 'NONSTRICT_READ_WRITE')]
class State
{
#[Id]
#[GeneratedValue]
#[Column]
protected int|null $id = null;
#[Column(unique: true)]
protected string $name;
#[Cache(usage: 'NONSTRICT_READ_WRITE')]
#[ManyToOne(targetEntity: Country::class)]
#[JoinColumn(name: 'country_id', referencedColumnName: 'id')]
protected Country|null $country = null;
/** @var Collection<int, City> */
#[Cache(usage: 'NONSTRICT_READ_WRITE')]
#[OneToMany(targetEntity: City::class, mappedBy: 'state')]
protected Collection $cities;
// other properties and methods
}
.. code-block:: annotation
<?php
/**
@@ -363,25 +403,26 @@ It caches the primary keys of association and cache each element will be cached
* @GeneratedValue
* @Column(type="integer")
*/
protected $id;
protected int|null $id = null;
/**
* @Column(unique=true)
*/
protected $name;
protected string $name;
/**
* @Cache("NONSTRICT_READ_WRITE")
* @ManyToOne(targetEntity="Country")
* @JoinColumn(name="country_id", referencedColumnName="id")
*/
protected $country;
protected Country|null $country;
/**
* @Cache("NONSTRICT_READ_WRITE")
* @OneToMany(targetEntity="City", mappedBy="state")
* @var Collection<int, City>
*/
protected $cities;
protected Collection $cities;
// other properties and methods
}
@@ -389,7 +430,10 @@ It caches the primary keys of association and cache each element will be cached
.. code-block:: xml
<?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">
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="https://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="State">
<cache usage="NONSTRICT_READ_WRITE" />
@@ -399,7 +443,7 @@ It caches the primary keys of association and cache each element will be cached
</id>
<field name="name" type="string" column="name"/>
<many-to-one field="country" target-entity="Country">
<cache usage="NONSTRICT_READ_WRITE" />
@@ -419,7 +463,7 @@ It caches the primary keys of association and cache each element will be cached
State:
type: entity
cache:
usage : NONSTRICT_READ_WRITE
usage: NONSTRICT_READ_WRITE
id:
id:
type: integer
@@ -437,17 +481,18 @@ It caches the primary keys of association and cache each element will be cached
country_id:
referencedColumnName: id
cache:
usage : NONSTRICT_READ_WRITE
usage: NONSTRICT_READ_WRITE
oneToMany:
cities:
targetEntity:City
mappedBy: state
cache:
usage : NONSTRICT_READ_WRITE
usage: NONSTRICT_READ_WRITE
.. note::
> Note: for this to work, the target entity must also be marked as cacheable.
for this to work, the target entity must also be marked as cacheable.
Cache usage
~~~~~~~~~~~
@@ -464,8 +509,8 @@ Basic entity cache
$country1 = $em->find('Country', 1); // Retrieve item from cache
$country->setName("New Name");
$em->persist($country);
$country1->setName('New Name');
$em->flush(); // Hit database to update the row and update cache
$em->clear(); // Clear entity manager
@@ -490,7 +535,7 @@ Association cache
$state = $em->find('State', 1);
// Hit database to update the row and update cache entry
$state->setName("New Name");
$state->setName('New Name');
$em->persist($state);
$em->flush();
@@ -541,14 +586,14 @@ The query cache stores the results of the query but as identifiers, entity value
.. code-block:: php
<?php
/* @var $em \Doctrine\ORM\EntityManager */
/** @var \Doctrine\ORM\EntityManager $em */
// Execute database query, store query cache and entity cache
$result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
->setCacheable(true)
->getResult();
$em->clear()
$em->clear();
// Check if query result is valid and load entities from cache
$result2 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
@@ -568,16 +613,16 @@ The Cache Mode controls how a particular query interacts with the second-level c
.. code-block:: php
<?php
/* @var $em \Doctrine\ORM\EntityManager */
/** @var \Doctrine\ORM\EntityManager $em */
// Will refresh the query cache and all entities the cache as it reads from the database.
$result1 = $em->createQuery('SELECT c FROM Country c ORDER BY c.name')
->setCacheMode(Cache::MODE_GET)
->setCacheMode(\Doctrine\ORM\Cache::MODE_GET)
->setCacheable(true)
->getResult();
.. note::
The the default query cache mode is ```Cache::MODE_NORMAL```
The default query cache mode is ```Cache::MODE_NORMAL```
DELETE / UPDATE queries
~~~~~~~~~~~~~~~~~~~~~~~
@@ -595,7 +640,7 @@ Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_
<?php
// Execute and invalidate
$this->_em->createQuery("UPDATE Entity\Country u SET u.name = 'unknown' WHERE u.id = 1")
->setHint(Query::HINT_CACHE_EVICT, true)
->setHint(\Doctrine\ORM\Query::HINT_CACHE_EVICT, true)
->execute();
@@ -657,7 +702,7 @@ However, you can use the cache API to check / invalidate cache entries.
.. code-block:: php
<?php
/* @var $cache \Doctrine\ORM\Cache */
/** @var \Doctrine\ORM\Cache $cache */
$cache = $em->getCache();
$cache->containsEntity('Entity\State', 1) // Check if the cache exists
@@ -681,40 +726,35 @@ For performance reasons the cache API does not extract from composite primary ke
.. code-block:: php
<?php
/**
* @Entity
*/
#[Entity]
class Reference
{
/**
* @Id
* @ManyToOne(targetEntity="Article", inversedBy="references")
* @JoinColumn(name="source_id", referencedColumnName="article_id")
*/
private $source;
#[Id]
#[ManyToOne(targetEntity: Article::class, inversedBy: 'references')]
#[JoinColumn(name: 'source_id', referencedColumnName: 'article_id')]
private Article|null $source = null;
/**
* @Id
* @ManyToOne(targetEntity="Article")
* @JoinColumn(name="target_id", referencedColumnName="article_id")
*/
#[Id]
#[ManyToOne(targetEntity: Article::class, inversedBy: 'references')]
#[JoinColumn(name: 'target_id', referencedColumnName: 'article_id')]
private $target;
}
// Supported
/* @var $article Article */
/** @var Article $article */
$article = $em->find('Article', 1);
// Supported
/* @var $article Article */
/** @var Article $article */
$article = $em->find('Article', $article);
// Supported
$id = array('source' => 1, 'target' => 2);
$id = ['source' => 1, 'target' => 2];
$reference = $em->find('Reference', $id);
// NOT Supported
$id = array('source' => new Article(1), 'target' => new Article(2));
$id = ['source' => new Article(1), 'target' => new Article(2)];
$reference = $em->find('Reference', $id);
Distributed environments

View File

@@ -10,7 +10,7 @@ we cannot protect you from SQL injection.
Please also read the documentation chapter on Security in Doctrine DBAL. This
page only handles Security issues in the ORM.
- `DBAL Security Page <http://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html>`
- `DBAL Security Page <https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/security.html>`
If you find a Security bug in Doctrine, please report it on Jira and change the
Security Level to "Security Issues". It will be visible to Doctrine Core
@@ -98,19 +98,20 @@ entity might look like this:
<?php
/**
* @Entity
*/
#[Entity]
class InsecureEntity
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @Column */
private $email;
/** @Column(type="boolean") */
private $isAdmin;
#[Id, Column, GeneratedValue]
private int|null $id = null;
public function fromArray(array $userInput)
#[Column]
private string $email;
#[Column]
private bool $isAdmin;
/** @param array<string, mixed> $userInput */
public function fromArray(array $userInput): void
{
foreach ($userInput as $key => $value) {
$this->$key = $value;
@@ -118,7 +119,7 @@ entity might look like this:
}
}
Now the possiblity of mass-asignment exists on this entity and can
Now the possiblity of mass-assignment exists on this entity and can
be exploited by attackers to set the "isAdmin" flag to true on any
object when you pass the whole request data to this method like:

View File

@@ -7,24 +7,10 @@ Doctrine Console
The Doctrine Console is a Command Line Interface tool for simplifying common
administration tasks during the development of a project that uses ORM.
Take a look at the :doc:`Installation and Configuration <configuration>`
chapter for more information how to setup the console command.
For the following examples, we will set up the CLI as ``bin/doctrine``.
Display Help Information
~~~~~~~~~~~~~~~~~~~~~~~~
Type ``php vendor/bin/doctrine`` on the command line and you should see an
overview of the available commands or use the --help flag to get
information on the available commands. If you want to know more
about the use of generate entities for example, you can call:
.. code-block:: php
$> php vendor/bin/doctrine orm:generate-entities --help
Configuration
~~~~~~~~~~~~~
Setting Up the Console
~~~~~~~~~~~~~~~~~~~~~~
Whenever the ``doctrine`` command line tool is invoked, it can
access all Commands that were registered by a developer. There is no
@@ -34,25 +20,33 @@ Doctrine DBAL and ORM. If you want to use additional commands you
have to register them yourself.
All the commands of the Doctrine Console require access to the
``EntityManager``. You have to inject it into the console application with
``ConsoleRunner::createHelperSet``. Whenever you invoke the Doctrine
binary, it searches the current directory for the file ``cli-config.php``.
This file contains the project-specific configuration.
``EntityManager``. You have to inject it into the console application.
Here is an example of a the project-specific ``cli-config.php``:
Here is an example of a the project-specific ``bin/doctrine`` binary.
.. code-block:: php
#!/usr/bin/env php
<?php
use Doctrine\ORM\Tools\Console\ConsoleRunner;
// replace this with the path to your own project bootstrap file.
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use Doctrine\ORM\Tools\Console\EntityManagerProvider\SingleManagerProvider;
// replace with path to your own project bootstrap file
require_once 'bootstrap.php';
// replace with mechanism to retrieve EntityManager in your app
$entityManager = GetEntityManager();
return ConsoleRunner::createHelperSet($entityManager);
$commands = [
// If you want to add your own custom console commands,
// you can do so here.
];
ConsoleRunner::run(
new SingleManagerProvider($entityManager),
$commands
);
.. note::
@@ -60,6 +54,18 @@ Here is an example of a the project-specific ``cli-config.php``:
and use their facilities to access the Doctrine EntityManager and
Connection Resources.
Display Help Information
~~~~~~~~~~~~~~~~~~~~~~~~
Type ``php bin/doctrine`` on the command line and you should see an
overview of the available commands or use the ``--help`` flag to get
information on the available commands. If you want to know more
about the use of generate entities for example, you can call:
::
$> php bin/doctrine orm:generate-entities --help
Command Overview
~~~~~~~~~~~~~~~~
@@ -143,7 +149,7 @@ When using the SchemaTool class directly, create your schema using
the ``createSchema()`` method. First create an instance of the
``SchemaTool`` and pass it an instance of the ``EntityManager``
that you want to use to create the schema. This method receives an
array of ``ClassMetadataInfo`` instances.
array of ``ClassMetadata`` instances.
.. code-block:: php
@@ -174,8 +180,8 @@ tables of the current model to clean up with orphaned tables.
You can also use database introspection to update your schema
easily with the ``updateSchema()`` method. It will compare your
existing database schema to the passed array of
``ClassMetadataInfo`` instances.
existing database schema to the passed array of ``ClassMetadata``
instances.
.. code-block:: php
@@ -189,38 +195,35 @@ To create the schema use the ``create`` command:
.. code-block:: php
$ php doctrine orm:schema-tool:create
$ php bin/doctrine orm:schema-tool:create
To drop the schema use the ``drop`` command:
.. code-block:: php
$ php doctrine orm:schema-tool:drop
$ php bin/doctrine orm:schema-tool:drop
If you want to drop and then recreate the schema then use both
options:
.. code-block:: php
$ php doctrine orm:schema-tool:drop
$ php doctrine orm:schema-tool:create
$ php bin/doctrine orm:schema-tool:drop
$ php bin/doctrine orm:schema-tool:create
As you would think, if you want to update your schema use the
``update`` command:
.. code-block:: php
$ php doctrine orm:schema-tool:update
$ php bin/doctrine orm:schema-tool:update
All of the above commands also accept a ``--dump-sql`` option that
will output the SQL for the ran operation.
.. code-block:: php
$ php doctrine orm:schema-tool:create --dump-sql
Before using the orm:schema-tool commands, remember to configure
your cli-config.php properly.
$ php bin/doctrine orm:schema-tool:create --dump-sql
Entity Generation
-----------------
@@ -229,9 +232,9 @@ Generate entity classes and method stubs from your mapping information.
.. code-block:: php
$ php doctrine orm:generate-entities
$ php doctrine orm:generate-entities --update-entities
$ php doctrine orm:generate-entities --regenerate-entities
$ php bin/doctrine orm:generate-entities
$ php bin/doctrine orm:generate-entities --update-entities
$ php bin/doctrine orm:generate-entities --regenerate-entities
This command is not suited for constant usage. It is a little helper and does
not support all the mapping edge cases very well. You still have to put work
@@ -316,14 +319,14 @@ convert to and the path to generate it:
.. code-block:: php
$ php doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
$ php bin/doctrine orm:convert-mapping xml /path/to/mapping-path-converted-to-xml
Reverse Engineering
-------------------
You can use the ``DatabaseDriver`` to reverse engineer a database
to an array of ``ClassMetadataInfo`` instances and generate YAML,
XML, etc. from them.
You can use the ``DatabaseDriver`` to reverse engineer a database to an
array of ``ClassMetadata`` instances and generate YAML, XML, etc. from
them.
.. note::
@@ -366,7 +369,7 @@ You can also reverse engineer a database using the
.. code-block:: php
$ php doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
$ php bin/doctrine orm:convert-mapping --from-database yml /path/to/mapping-path-converted-to-yml
.. note::
@@ -393,6 +396,11 @@ You can either use the Doctrine Command Line Tool:
doctrine orm:validate-schema
If the validation fails, you can change the verbosity level to
check the detected errors:
doctrine orm:validate-schema -v
Or you can trigger the validation manually:
.. code-block:: php

View File

@@ -68,7 +68,7 @@ looks like this:
// $em instanceof EntityManager
$em->getConnection()->beginTransaction(); // suspend auto-commit
try {
//... do some work
// ... do some work
$user = new User;
$user->setName('George');
$em->persist($user);
@@ -98,7 +98,7 @@ functionally equivalent to the previously shown code looks as follows:
<?php
// $em instanceof EntityManager
$em->transactional(function($em) {
//... do some work
// ... do some work
$user = new User;
$user->setName('George');
$em->persist($user);
@@ -114,8 +114,8 @@ functionally equivalent to the previously shown code looks as follows:
The difference between ``Connection#transactional($func)`` and
``EntityManager#transactional($func)`` is that the latter
abstraction flushes the ``EntityManager`` prior to transaction
commit and rolls back the transaction when an
exception occurs.
commit and in case of an exception the ``EntityManager`` gets closed
in addition to the transaction rollback.
.. _transactions-and-concurrency_exception-handling:
@@ -189,14 +189,25 @@ example we'll use an integer.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class User
{
// ...
#[Version, Column(type: 'integer')]
private int $version;
// ...
}
.. code-block:: annotation
<?php
class User
{
// ...
/** @Version @Column(type="integer") */
private $version;
private int $version;
// ...
}
@@ -222,14 +233,25 @@ timestamp or datetime):
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
class User
{
// ...
#[Version, Column(type: 'datetime')]
private DateTime $version;
// ...
}
.. code-block:: annotation
<?php
class User
{
// ...
/** @Version @Column(type="datetime") */
private $version;
private DateTime $version;
// ...
}
@@ -279,15 +301,15 @@ either when calling ``EntityManager#find()``:
<?php
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\OptimisticLockException;
$theEntityId = 1;
$expectedVersion = 184;
try {
$entity = $em->find('User', $theEntityId, LockMode::OPTIMISTIC, $expectedVersion);
// do the work
$em->flush();
} catch(OptimisticLockException $e) {
echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
@@ -300,16 +322,16 @@ Or you can use ``EntityManager#lock()`` to find out:
<?php
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\OptimisticLockException;
$theEntityId = 1;
$expectedVersion = 184;
$entity = $em->find('User', $theEntityId);
try {
// assert version
$em->lock($entity, LockMode::OPTIMISTIC, $expectedVersion);
} catch(OptimisticLockException $e) {
echo "Sorry, but someone else has already changed this entity. Please apply the changes again!";
}
@@ -348,7 +370,7 @@ See the example code, The form (GET Request):
<?php
$post = $em->find('BlogPost', 123456);
echo '<input type="hidden" name="id" value="' . $post->getId() . '" />';
echo '<input type="hidden" name="version" value="' . $post->getCurrentVersion() . '" />';
@@ -359,7 +381,7 @@ And the change headline action (POST Request):
<?php
$postId = (int)$_GET['id'];
$postVersion = (int)$_GET['version'];
$post = $em->find('BlogPost', $postId, \Doctrine\DBAL\LockMode::OPTIMISTIC, $postVersion);
.. _transactions-and-concurrency_pessimistic-locking:
@@ -390,7 +412,7 @@ Doctrine ORM currently supports two pessimistic lock modes:
locks other concurrent requests that attempt to update or lock rows
in write mode.
You can use pessimistic locks in three different scenarios:
You can use pessimistic locks in four different scenarios:
1. Using
@@ -402,8 +424,10 @@ You can use pessimistic locks in three different scenarios:
or
``EntityManager#lock($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``
3. Using
``EntityManager#refresh($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)``
or
``EntityManager#refresh($entity, \Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``
4. Using
``Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_WRITE)``
or
``Query#setLockMode(\Doctrine\DBAL\LockMode::PESSIMISTIC_READ)``

View File

@@ -0,0 +1,179 @@
Implementing a TypedFieldMapper
===============================
.. versionadded:: 2.14
You can specify custom typed field mapping between PHP type and DBAL type using ``Doctrine\ORM\Configuration``
and a custom ``Doctrine\ORM\Mapping\TypedFieldMapper`` implementation.
.. code-block:: php
<?php
$configuration->setTypedFieldMapper(new CustomTypedFieldMapper());
DefaultTypedFieldMapper
-----------------------
By default the ``Doctrine\ORM\Mapping\DefaultTypedFieldMapper`` is used, and you can pass an array of
PHP type => DBAL type mappings into its constructor to override the default behavior or add new mappings.
.. code-block:: php
<?php
use App\CustomIds\CustomIdObject;
use App\DBAL\Type\CustomIdObjectType;
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
CustomIdObject::class => CustomIdObjectType::class,
]));
Then, an entity using the ``CustomIdObject`` typed field will be correctly assigned its DBAL type
(``CustomIdObjectType``) without the need of explicit declaration.
.. configuration-block::
.. code-block:: attribute
<?php
#[ORM\Entity]
#[ORM\Table(name: 'cms_users_typed_with_custom_typed_field')]
class UserTypedWithCustomTypedField
{
#[ORM\Column]
public CustomIdObject $customId;
// ...
}
.. code-block:: annotation
<?php
/**
* @Entity
* @Table(name="cms_users_typed_with_custom_typed_field")
*/
class UserTypedWithCustomTypedField
{
/** @Column */
public CustomIdObject $customId;
// ...
}
.. code-block:: xml
<doctrine-mapping>
<entity name="UserTypedWithCustomTypedField">
<field name="customId"/>
<!-- -->
</entity>
</doctrine-mapping>
.. code-block:: yaml
UserTypedWithCustomTypedField:
type: entity
fields:
customId: ~
It is perfectly valid to override even the "automatic" mapping rules mentioned above:
.. code-block:: php
<?php
use App\DBAL\Type\CustomIntType;
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
$configuration->setTypedFieldMapper(new DefaultTypedFieldMapper([
'int' => CustomIntType::class,
]));
.. note::
If chained, once the first ``TypedFieldMapper`` assigns a type to a field, the ``DefaultTypedFieldMapper`` will
ignore its mapping and not override it anymore (if it is later in the chain). See below for chaining type mappers.
TypedFieldMapper interface
-------------------------
The interface ``Doctrine\ORM\Mapping\TypedFieldMapper`` allows you to implement your own
typed field mapping logic. It consists of just one function
.. code-block:: php
<?php
/**
* Validates & completes the given field mapping based on typed property.
*
* @param array{fieldName: string, enumType?: string, type?: mixed} $mapping The field mapping to validate & complete.
* @param \ReflectionProperty $field
*
* @return array{fieldName: string, enumType?: string, type?: mixed} The updated mapping.
*/
public function validateAndComplete(array $mapping, ReflectionProperty $field): array;
ChainTypedFieldMapper
---------------------
The class ``Doctrine\ORM\Mapping\ChainTypedFieldMapper`` allows you to chain multiple ``TypedFieldMapper`` instances.
When being evaluated, the ``TypedFieldMapper::validateAndComplete`` is called in the order in which
the instances were supplied to the ``ChainTypedFieldMapper`` constructor.
.. code-block:: php
<?php
use App\DBAL\Type\CustomIntType;
use Doctrine\ORM\Mapping\ChainTypedFieldMapper;
use Doctrine\ORM\Mapping\DefaultTypedFieldMapper;
$configuration->setTypedFieldMapper(
new ChainTypedFieldMapper(
new DefaultTypedFieldMapper(['int' => CustomIntType::class,]),
new CustomTypedFieldMapper()
)
);
Implementing a TypedFieldMapper
-------------------------------
If you want to assign all ``BackedEnum`` fields to your custom ``BackedEnumDBALType`` or you want to use different
DBAL types based on whether the entity field is nullable or not, you can achieve this by implementing your own
typed field mapper.
You need to create a class which implements ``Doctrine\ORM\Mapping\TypedFieldMapper``.
.. code-block:: php
<?php
final class CustomEnumTypedFieldMapper implements TypedFieldMapper
{
/**
* {@inheritDoc}
*/
public function validateAndComplete(array $mapping, ReflectionProperty $field): array
{
$type = $field->getType();
if (
! isset($mapping['type'])
&& ($type instanceof ReflectionNamedType)
) {
if (! $type->isBuiltin() && enum_exists($type->getName())) {
$mapping['type'] = BackedEnumDBALType::class;
}
}
return $mapping;
}
}
.. note::
Note that this case checks whether the mapping is already assigned, and if yes, it skips it. This is up to your
implementation. You can make a "greedy" mapper which will always override the mapping with its own type, or one
that behaves like the ``DefaultTypedFieldMapper`` and does not modify the type once its set prior in the chain.

View File

@@ -16,11 +16,11 @@ Bidirectional Associations
The following rules apply to **bidirectional** associations:
- The inverse side has to have the ``mappedBy`` attribute of the OneToOne,
OneToMany, or ManyToMany mapping declaration. The mappedBy
OneToMany, or ManyToMany mapping declaration. The ``mappedBy``
attribute contains the name of the association-field on the owning side.
- The owning side has to have the ``inversedBy`` attribute of the
OneToOne, ManyToOne, or ManyToMany mapping declaration.
The inversedBy attribute contains the name of the association-field
OneToOne, ManyToOne, or ManyToMany mapping declaration.
The ``inversedBy`` attribute contains the name of the association-field
on the inverse-side.
- ManyToOne is always the owning side of a bidirectional association.
- OneToMany is always the inverse side of a bidirectional association.

View File

@@ -17,7 +17,7 @@ ask for an entity with a specific ID twice, it will return the same instance:
.. code-block:: php
public function testIdentityMap()
public function testIdentityMap(): void
{
$objectA = $this->entityManager->find('EntityName', 1);
$objectB = $this->entityManager->find('EntityName', 1);
@@ -34,11 +34,11 @@ will still end up with the same reference:
.. code-block:: php
public function testIdentityMapReference()
public function testIdentityMapReference(): void
{
$objectA = $this->entityManager->getReference('EntityName', 1);
// check for proxyinterface
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $objectA);
// check entity is not initialized
$this->assertTrue($this->entityManager->isUninitializedObject($objectA));
$objectB = $this->entityManager->find('EntityName', 1);
@@ -104,7 +104,7 @@ How Doctrine Detects Changes
Doctrine is a data-mapper that tries to achieve persistence-ignorance (PI).
This means you map php objects into a relational database that don't
necessarily know about the database at all. A natural question would now be,
"how does Doctrine even detect objects have changed?".
"how does Doctrine even detect objects have changed?".
For this Doctrine keeps a second map inside the UnitOfWork. Whenever you fetch
an object from the database Doctrine will keep a copy of all the properties and
@@ -134,6 +134,10 @@ optimize the performance of the Flush Operation:
explicit strategies of notifying the UnitOfWork what objects/properties
changed.
.. note::
Flush only a single entity with ``$entityManager->flush($entity)`` is deprecated and will be removed in ORM 3.0.
(\ `Details <https://github.com/doctrine/orm/issues/8459>`_)
Query Internals
---------------
@@ -198,4 +202,3 @@ ClassMetadataFactory
~~~~~~~~~~~~~~~~~~~~
tbr

View File

@@ -32,62 +32,62 @@ information about its type and if it's the owning or inverse side.
.. code-block:: php
<?php
/** @Entity */
#[Entity]
class User
{
/** @Id @GeneratedValue @Column(type="string") */
private $id;
#[Id, GeneratedValue, Column]
private int|null $id = null;
/**
* Bidirectional - Many users have Many favorite comments (OWNING SIDE)
*
* @ManyToMany(targetEntity="Comment", inversedBy="userFavorites")
* @JoinTable(name="user_favorite_comments")
* @var Collection<int, Comment>
*/
private $favorites;
#[ManyToMany(targetEntity: Comment::class, inversedBy: 'userFavorites')]
#[JoinTable(name: 'user_favorite_comments')]
private Collection $favorites;
/**
* Unidirectional - Many users have marked many comments as read
*
* @ManyToMany(targetEntity="Comment")
* @JoinTable(name="user_read_comments")
* @var Collection<int, Comment>
*/
private $commentsRead;
#[ManyToMany(targetEntity: Comment::class)]
#[JoinTable(name: 'user_read_comments')]
private Collection $commentsRead;
/**
* Bidirectional - One-To-Many (INVERSE SIDE)
*
* @OneToMany(targetEntity="Comment", mappedBy="author")
* @var Collection<int, Comment>
*/
private $commentsAuthored;
/**
* Unidirectional - Many-To-One
*
* @ManyToOne(targetEntity="Comment")
*/
private $firstComment;
#[OneToMany(targetEntity: Comment::class, mappedBy: 'author')]
private Collection $commentsAuthored;
/** Unidirectional - Many-To-One */
#[ManyToOne(targetEntity: Comment::class)]
private Comment|null $firstComment = null;
}
/** @Entity */
#[Entity]
class Comment
{
/** @Id @GeneratedValue @Column(type="string") */
private $id;
#[Id, GeneratedValue, Column]
private string $id;
/**
* Bidirectional - Many comments are favorited by many users (INVERSE SIDE)
*
* @ManyToMany(targetEntity="User", mappedBy="favorites")
* @var Collection<int, User>
*/
private $userFavorites;
#[ManyToMany(targetEntity: User::class, mappedBy: 'favorites')]
private Collection $userFavorites;
/**
* Bidirectional - Many Comments are authored by one user (OWNING SIDE)
*
* @ManyToOne(targetEntity="User", inversedBy="commentsAuthored")
*/
private $author;
#[ManyToOne(targetEntity: User::class, inversedBy: 'commentsAuthored')]
private User|null $author = null;
}
This two entities generate the following MySQL Schema (Foreign Key
@@ -100,19 +100,19 @@ definitions omitted):
firstComment_id VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE Comment (
id VARCHAR(255) NOT NULL,
author_id VARCHAR(255) DEFAULT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE user_favorite_comments (
user_id VARCHAR(255) NOT NULL,
favorite_comment_id VARCHAR(255) NOT NULL,
PRIMARY KEY(user_id, favorite_comment_id)
) ENGINE = InnoDB;
CREATE TABLE user_read_comments (
user_id VARCHAR(255) NOT NULL,
comment_id VARCHAR(255) NOT NULL,
@@ -132,11 +132,12 @@ relations of the ``User``:
class User
{
// ...
public function getReadComments() {
/** @return Collection<int, Comment> */
public function getReadComments(): Collection {
return $this->commentsRead;
}
public function setFirstComment(Comment $c) {
public function setFirstComment(Comment $c): void {
$this->firstComment = $c;
}
}
@@ -148,17 +149,17 @@ The interaction code would then look like in the following snippet
<?php
$user = $em->find('User', $userId);
// unidirectional many to many
$comment = $em->find('Comment', $readCommentId);
$user->getReadComments()->add($comment);
$em->flush();
// unidirectional many to one
$myFirstComment = new Comment();
$user->setFirstComment($myFirstComment);
$em->persist($myFirstComment);
$em->flush();
@@ -171,40 +172,43 @@ fields on both sides:
class User
{
// ..
public function getAuthoredComments() {
/** @return Collection<int, Comment> */
public function getAuthoredComments(): Collection {
return $this->commentsAuthored;
}
public function getFavoriteComments() {
/** @return Collection<int, Comment> */
public function getFavoriteComments(): Collection {
return $this->favorites;
}
}
class Comment
{
// ...
public function getUserFavorites() {
/** @return Collection<int, User> */
public function getUserFavorites(): Collection {
return $this->userFavorites;
}
public function setAuthor(User $author = null) {
public function setAuthor(User|null $author = null): void {
$this->author = $author;
}
}
// Many-to-Many
$user->getFavorites()->add($favoriteComment);
$favoriteComment->getUserFavorites()->add($user);
$em->flush();
// Many-To-One / One-To-Many Bidirectional
$newComment = new Comment();
$user->getAuthoredComments()->add($newComment);
$newComment->setAuthor($user);
$em->persist($newComment);
$em->flush();
@@ -225,10 +229,10 @@ element. Here are some examples:
// Remove by Elements
$user->getComments()->removeElement($comment);
$comment->setAuthor(null);
$user->getFavorites()->removeElement($comment);
$comment->getUserFavorites()->removeElement($user);
// Remove by Key
$user->getComments()->remove($ithComment);
$comment->setAuthor(null);
@@ -240,7 +244,7 @@ Notice how both sides of the bidirectional association are always
updated. Unidirectional associations are consequently simpler to
handle.
Also note that if you use type-hinting in your methods, you will
Also note that if you use type-hinting in your methods, you will
have to specify a nullable type, i.e. ``setAddress(?Address $address)``,
otherwise ``setAddress(null)`` will fail to remove the association.
Another way to deal with this is to provide a special method, like
@@ -271,8 +275,8 @@ entities that have been re-added to the collection.
Say you clear a collection of tags by calling
``$post->getTags()->clear();`` and then call
``$post->getTags()->add($tag)``. This will not recognize the tag having
already been added previously and will consequently issue two separate database
``$post->getTags()->add($tag)``. This will not recognize the tag having
already been added previously and will consequently issue two separate database
calls.
Association Management Methods
@@ -291,44 +295,44 @@ example that encapsulate much of the association management code:
<?php
class User
{
//...
public function markCommentRead(Comment $comment) {
// ...
public function markCommentRead(Comment $comment): void {
// Collections implement ArrayAccess
$this->commentsRead[] = $comment;
}
public function addComment(Comment $comment) {
public function addComment(Comment $comment): void {
if (count($this->commentsAuthored) == 0) {
$this->setFirstComment($comment);
}
$this->comments[] = $comment;
$comment->setAuthor($this);
}
private function setFirstComment(Comment $c) {
private function setFirstComment(Comment $c): void {
$this->firstComment = $c;
}
public function addFavorite(Comment $comment) {
public function addFavorite(Comment $comment): void {
$this->favorites->add($comment);
$comment->addUserFavorite($this);
}
public function removeFavorite(Comment $comment) {
public function removeFavorite(Comment $comment): void {
$this->favorites->removeElement($comment);
$comment->removeUserFavorite($this);
}
}
class Comment
{
// ..
public function addUserFavorite(User $user) {
public function addUserFavorite(User $user): void {
$this->userFavorites[] = $user;
}
public function removeUserFavorite(User $user) {
public function removeUserFavorite(User $user): void {
$this->userFavorites->removeElement($user);
}
}
@@ -356,7 +360,8 @@ the details inside the classes can be challenging.
<?php
class User {
public function getReadComments() {
/** @return array<int, Comment> */
public function getReadComments(): array {
return $this->commentsRead->toArray();
}
}
@@ -373,7 +378,7 @@ as your preferences.
Synchronizing Bidirectional Collections
---------------------------------------
In the case of Many-To-Many associations you as the developer have the
In the case of Many-To-Many associations you as the developer have the
responsibility of keeping the collections on the owning and inverse side
in sync when you apply changes to them. Doctrine can only
guarantee a consistent state for the hydration, not for your client
@@ -387,7 +392,7 @@ can show the possible caveats you can encounter:
<?php
$user->getFavorites()->add($favoriteComment);
// not calling $favoriteComment->getUserFavorites()->add($user);
$user->getFavorites()->contains($favoriteComment); // TRUE
$favoriteComment->getUserFavorites()->contains($user); // FALSE
@@ -422,7 +427,7 @@ comment might look like in your controller (without ``cascade: persist``):
$user = new User();
$myFirstComment = new Comment();
$user->addComment($myFirstComment);
$em->persist($user);
$em->persist($myFirstComment); // required, if `cascade: persist` is not set
$em->flush();
@@ -437,8 +442,10 @@ only accessing it through the User entity:
// User entity
class User
{
private $id;
private $comments;
private int $id;
/** @var Collection<int, Comment> */
private Collection $comments;
public function __construct()
{
@@ -463,14 +470,11 @@ If you then set up the cascading to the ``User#commentsAuthored`` property...
<?php
class User
{
//...
/**
* Bidirectional - One-To-Many (INVERSE SIDE)
*
* @OneToMany(targetEntity="Comment", mappedBy="author", cascade={"persist", "remove"})
*/
// ...
/** Bidirectional - One-To-Many (INVERSE SIDE) */
#[OneToMany(targetEntity: Comment::class, mappedBy: 'author', cascade: ['persist', 'remove'])]
private $commentsAuthored;
//...
// ...
}
...you can now create a user and an associated comment like this:
@@ -480,7 +484,7 @@ If you then set up the cascading to the ``User#commentsAuthored`` property...
<?php
$user = new User();
$user->comment('Lorem ipsum', new DateTime());
$em->persist($user);
$em->flush();
@@ -521,6 +525,8 @@ For each cascade operation that gets activated, Doctrine also
applies that operation to the association, be it single or
collection valued.
.. _persistence-by-reachability:
Persistence by Reachability: Cascade Persist
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -557,6 +563,13 @@ OrphanRemoval works with one-to-one, one-to-many and many-to-many associations.
If you neglect this assumption your entities will get deleted by Doctrine even if
you assigned the orphaned entity to another one.
.. note::
``orphanRemoval=true`` option should be used in combination with ``cascade=["persist"]`` option
as the child entity, that is manually persisted, will not be deleted automatically by Doctrine
when a collection is still an instance of ArrayCollection (before first flush / hydration).
This is a Doctrine limitation since ArrayCollection does not have access to a UnitOfWork.
As a better example consider an Addressbook application where you have Contacts, Addresses
and StandingData:
@@ -568,31 +581,30 @@ and StandingData:
use Doctrine\Common\Collections\ArrayCollection;
/**
* @Entity
*/
#[Entity]
class Contact
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
#[Id, Column(type: 'integer'), GeneratedValue]
private int|null $id = null;
/** @OneToOne(targetEntity="StandingData", orphanRemoval=true) */
private $standingData;
#[OneToOne(targetEntity: StandingData::class, cascade: ['persist'], orphanRemoval: true)]
private StandingData|null $standingData = null;
/** @OneToMany(targetEntity="Address", mappedBy="contact", orphanRemoval=true) */
private $addresses;
/** @var Collection<int, Address> */
#[OneToMany(targetEntity: Address::class, mappedBy: 'contact', cascade: ['persist'], orphanRemoval: true)]
private Collection $addresses;
public function __construct()
{
$this->addresses = new ArrayCollection();
}
public function newStandingData(StandingData $sd)
public function newStandingData(StandingData $sd): void
{
$this->standingData = $sd;
}
public function removeAddress($pos)
public function removeAddress(int $pos): void
{
unset($this->addresses[$pos]);
}
@@ -610,10 +622,10 @@ Now two examples of what happens when you remove the references:
$em->flush();
In this case you have not only changed the ``Contact`` entity itself but
you have also removed the references for standing data and as well as one
address reference. When flush is called not only are the references removed
but both the old standing data and the one address entity are also deleted
In this case you have not only changed the ``Contact`` entity itself but
you have also removed the references for standing data and as well as one
address reference. When flush is called not only are the references removed
but both the old standing data and the one address entity are also deleted
from the database.
.. _filtering-collections:
@@ -706,6 +718,7 @@ methods:
* ``andX($arg1, $arg2, ...)``
* ``orX($arg1, $arg2, ...)``
* ``not($expression)``
* ``eq($field, $value)``
* ``gt($field, $value)``
* ``lt($field, $value)``

View File

@@ -27,7 +27,7 @@ Work that have not yet been persisted are lost.
.. note::
Doctrine does NEVER touch the public API of methods in your entity
Doctrine NEVER touches the public API of methods in your entity
classes (like getters and setters) nor the constructor method.
Instead, it uses reflection to get/set data from/to your entity objects.
When Doctrine fetches data from DB and saves it back,
@@ -95,28 +95,29 @@ from newly opened EntityManager.
.. code-block:: php
<?php
/** @Entity */
#[Entity]
class Article
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
#[Id, Column(type: 'integer'), GeneratedValue]
private int|null $id = null;
/** @Column(type="string") */
private $headline;
#[Column(type: 'string')]
private string $headline;
/** @ManyToOne(targetEntity="User") */
private $author;
#[ManyToOne(targetEntity: User::class)]
private User|null $author = null;
/** @OneToMany(targetEntity="Comment", mappedBy="article") */
private $comments;
/** @var Collection<int, Comment> */
#[OneToMany(targetEntity: Comment::class, mappedBy: 'article')]
private Collection $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
public function getAuthor() { return $this->author; }
public function getComments() { return $this->comments; }
public function getAuthor(): User|null { return $this->author; }
public function getComments(): Collection { return $this->comments; }
}
$article = $em->find('Article', 1);
@@ -161,28 +162,6 @@ your code. See the following code:
echo "This will always be true!";
}
A slice of the generated proxy classes code looks like the
following piece of code. A real proxy class override ALL public
methods along the lines of the ``getName()`` method shown below:
.. code-block:: php
<?php
class UserProxy extends User implements Proxy
{
private function _load()
{
// lazy loading code
}
public function getName()
{
$this->_load();
return parent::getName();
}
// .. other public methods of User
}
.. warning::
Traversing the object graph for parts that are lazy-loaded will
@@ -213,6 +192,11 @@ be properly synchronized with the database when
database in the most efficient way and a single, short transaction,
taking care of maintaining referential integrity.
.. note::
Do not make any assumptions in your code about the number of queries
it takes to flush changes, about the ordering of ``INSERT``, ``UPDATE``
and ``DELETE`` queries or the order in which entities will be processed.
Example:
@@ -304,20 +288,56 @@ as follows:
- A removed entity X will be removed from the database as a result
of the flush operation.
After an entity has been removed its in-memory state is the same as
After an entity has been removed, its in-memory state is the same as
before the removal, except for generated identifiers.
Removing an entity will also automatically delete any existing
records in many-to-many join tables that link this entity. The
action taken depends on the value of the ``@joinColumn`` mapping
attribute "onDelete". Either Doctrine issues a dedicated ``DELETE``
statement for records of each join table or it depends on the
foreign key semantics of onDelete="CASCADE".
During the ``EntityManager#flush()`` operation, the removed entity
will also be removed from all collections in entities currently
loaded into memory.
.. _remove_object_many_to_many_join_tables:
Join-table management when removing from many-to-many collections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Regarding existing rows in many-to-many join tables that refer to
an entity being removed, the following applies.
When the entity being removed does not declare the many-to-many association
itself (that is, the many-to-many association is unidirectional and
the entity is on the inverse side), the ORM has no reasonable way to
detect associations targeting the entity's class. Thus, no ORM-level handling
of join-table rows is attempted and database-level constraints apply.
In case of database-level ``ON DELETE RESTRICT`` constraints, the
``EntityManager#flush()`` operation may abort and a ``ConstraintViolationException``
may be thrown. No in-memory collections will be modified in this case.
With ``ON DELETE CASCADE``, the RDBMS will take care of removing rows
from join tables.
When the entity being removed is part of bi-directional many-to-many
association, either as the owning or inverse side, the ORM will
delete rows from join tables before removing the entity itself. That means
database-level ``ON DELETE RESTRICT`` constraints on join tables are not
effective, since the join table rows are removed first. Removal of join table
rows happens through specialized methods in entity and collection persister
classes and take one query per entity and join table. In case the association
uses a ``@JoinColumn`` configuration with ``onDelete="CASCADE"``, instead
of using a dedicated ``DELETE`` query the database-level operation will be
relied upon.
.. note::
In case you rely on database-level ``ON DELETE RESTRICT`` constraints,
be aware that by making many-to-many associations bidirectional the
assumed protection may be lost.
Performance of different deletion strategies
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Deleting an object with all its associated objects can be achieved
in multiple ways with very different performance impacts.
1. If an association is marked as ``CASCADE=REMOVE`` Doctrine ORM
will fetch this association. If its a Single association it will
pass this entity to
@@ -338,9 +358,9 @@ in multiple ways with very different performance impacts.
.. note::
Calling ``remove`` on an entity will remove the object from the identiy
map and therefore detach it. Querying the same entity again, for example
via a lazy loaded relation, will return a new object.
Calling ``remove`` on an entity will remove the object from the identity
map and therefore detach it. Querying the same entity again, for example
via a lazy loaded relation, will return a new object.
Detaching entities
@@ -388,8 +408,7 @@ automatically without invoking the ``detach`` method:
currently managed by the EntityManager instance become detached.
- When serializing an entity. The entity retrieved upon subsequent
unserialization will be detached (This is the case for all entities
that are serialized and stored in some cache, i.e. when using the
Query Result Cache).
that are serialized and stored in some cache).
The ``detach`` operation is usually not as frequently needed and
used as ``persist`` and ``remove``.
@@ -414,14 +433,6 @@ Example:
// $entity now refers to the fully managed copy returned by the merge operation.
// The EntityManager $em now manages the persistence of $entity as usual.
.. note::
When you want to serialize/unserialize entities you
have to make all entity properties protected, never private. The
reason for this is, if you serialize a class that was a proxy
instance before, the private variables won't be serialized and a
PHP Notice is thrown.
The semantics of the merge operation, applied to an entity X, are
as follows:
@@ -834,7 +845,7 @@ By default the EntityManager returns a default implementation of
``Doctrine\ORM\EntityRepository`` when you call
``EntityManager#getRepository($entityClass)``. You can overwrite
this behaviour by specifying the class name of your own Entity
Repository in the Annotation, XML or YAML metadata. In large
Repository in the Attribute, Annotation, XML or YAML metadata. In large
applications that require lots of specialized DQL queries using a
custom repository is one recommended way of grouping these queries
in a central location.
@@ -844,12 +855,11 @@ in a central location.
<?php
namespace MyDomain\Model;
use MyDomain\Model\UserRepository;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="MyDomain\Model\UserRepository")
*/
#[ORM\Entity(repositoryClass: UserRepository::class)]
class User
{
@@ -857,7 +867,8 @@ in a central location.
class UserRepository extends EntityRepository
{
public function getAllAdminUsers()
/** @return Collection<User> */
public function getAllAdminUsers(): Collection
{
return $this->_em->createQuery('SELECT u FROM MyDomain\Model\User u WHERE u.status = "admin"')
->getResult();
@@ -872,5 +883,3 @@ You can access your repository now by calling:
// $em instanceof EntityManager
$admins = $em->getRepository('MyDomain\Model\User')->getAllAdminUsers();

View File

@@ -17,7 +17,7 @@ setup for the latest code in trunk.
.. code-block:: xml
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="https://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">
@@ -103,7 +103,7 @@ of several common elements:
// Doctrine.Tests.ORM.Mapping.User.dcm.xml
<?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"
xmlns:xsi="https://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">
@@ -256,6 +256,11 @@ Optional attributes:
table? Defaults to false.
- nullable - Should this field allow NULL as a value? Defaults to
false.
- insertable - Should this field be inserted? Defaults to true.
- updatable - Should this field be updated? Defaults to true.
- generated - Enum of the values ALWAYS, INSERT, NEVER that determines if
generated value must be fetched from database after INSERT or UPDATE.
Defaults to "NEVER".
- version - Should this field be used for optimistic locking? Only
works on fields with type integer or datetime.
- scale - Scale of a decimal type.
@@ -689,6 +694,7 @@ specified by their respective tags:
- ``<cascade-merge />``
- ``<cascade-remove />``
- ``<cascade-refresh />``
- ``<cascade-detach />``
Join Column Element
~~~~~~~~~~~~~~~~~~~
@@ -764,7 +770,7 @@ entity relationship. You can define this in XML with the "association-key" attri
.. code-block:: xml
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="https://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">

View File

@@ -1,7 +1,7 @@
YAML Mapping
============
.. note::
.. warning::
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.

View File

@@ -41,9 +41,10 @@
reference/native-sql
reference/change-tracking-policies
reference/partial-objects
reference/annotations-reference
reference/attributes-reference
reference/xml-mapping
reference/yaml-mapping
reference/annotations-reference
reference/php-mapping
reference/caching
reference/improving-performance
@@ -72,7 +73,6 @@
cookbook/dql-user-defined-functions
cookbook/implementing-arrayaccess-for-domain-objects
cookbook/implementing-the-notify-changetracking-policy
cookbook/implementing-wakeup-or-clone
cookbook/resolve-target-entity-listener
cookbook/sql-table-prefixes
cookbook/strategy-cookbook-introduction

View File

@@ -1,86 +0,0 @@
Welcome to Doctrine 2 ORM's documentation!
==========================================
Tutorials
---------
.. toctree::
:maxdepth: 1
tutorials/getting-started
tutorials/getting-started-database
tutorials/getting-started-models
tutorials/working-with-indexed-associations
tutorials/extra-lazy-associations
tutorials/composite-primary-keys
tutorials/ordered-associations
tutorials/override-field-association-mappings-in-subclasses
tutorials/pagination.rst
tutorials/embeddables.rst
Reference Guide
---------------
.. toctree::
:maxdepth: 1
:numbered:
reference/architecture
reference/configuration.rst
reference/faq
reference/basic-mapping
reference/association-mapping
reference/inheritance-mapping
reference/working-with-objects
reference/working-with-associations
reference/events
reference/unitofwork
reference/unitofwork-associations
reference/transactions-and-concurrency
reference/batch-processing
reference/dql-doctrine-query-language
reference/query-builder
reference/native-sql
reference/change-tracking-policies
reference/partial-objects
reference/xml-mapping
reference/yaml-mapping
reference/annotations-reference
reference/php-mapping
reference/caching
reference/improving-performance
reference/tools
reference/metadata-drivers
reference/best-practices
reference/limitations-and-known-issues
tutorials/pagination
reference/filters
reference/namingstrategy
reference/advanced-configuration
reference/second-level-cache
reference/security
Cookbook
--------
.. toctree::
:maxdepth: 1
cookbook/aggregate-fields
cookbook/custom-mapping-types
cookbook/decorator-pattern
cookbook/dql-custom-walkers
cookbook/dql-user-defined-functions
cookbook/implementing-arrayaccess-for-domain-objects
cookbook/implementing-the-notify-changetracking-policy
cookbook/implementing-wakeup-or-clone
cookbook/resolve-target-entity-listener
cookbook/sql-table-prefixes
cookbook/strategy-cookbook-introduction
cookbook/validation-of-entities
cookbook/working-with-datetime
cookbook/mysql-enums
cookbook/advanced-field-value-conversion-using-custom-mapping-types
cookbook/entities-in-session

View File

@@ -23,7 +23,34 @@ and year of production as primary keys:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace VehicleCatalogue\Model;
#[Entity]
class Car
{
public function __construct(
#[Id, Column]
private string $name,
#[Id, Column]
private int $year,
) {
}
public function getModelName(): string
{
return $this->name;
}
public function getYearOfProduction(): int
{
return $this->year;
}
}
.. code-block:: annotation
<?php
namespace VehicleCatalogue\Model;
@@ -34,9 +61,9 @@ and year of production as primary keys:
class Car
{
/** @Id @Column(type="string") */
private $name;
private string $name;
/** @Id @Column(type="integer") */
private $year;
private int $year;
public function __construct($name, $year)
{
@@ -44,12 +71,12 @@ and year of production as primary keys:
$this->year = $year;
}
public function getModelName()
public function getModelName(): string
{
return $this->name;
}
public function getYearOfProduction()
public function getYearOfProduction(): int
{
return $this->year;
}
@@ -59,7 +86,7 @@ and year of production as primary keys:
<?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"
xmlns:xsi="https://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">
@@ -104,7 +131,7 @@ And for querying you can use arrays to both DQL and EntityRepositories:
$dql = "SELECT c FROM VehicleCatalogue\Model\Car c WHERE c.id = ?1";
$audi = $em->createQuery($dql)
->setParameter(1, array("name" => "Audi A8", "year" => 2010))
->setParameter(1, ["name" => "Audi A8", "year" => 2010])
->getSingleResult();
You can also use this entity in associations. Doctrine will then generate two foreign keys one for ``name``
@@ -131,7 +158,7 @@ of one or many parent entities.
The semantics of mapping identity through foreign entities are easy:
- Only allowed on Many-To-One or One-To-One associations.
- Plug an ``@Id`` annotation onto every association.
- Plug an ``#[Id]`` attribute onto every association.
- Set an attribute ``association-key`` with the field name of the association in XML.
- Set a key ``associationKey:`` with the field name of the association in YAML.
@@ -142,7 +169,52 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace Application\Model;
use Doctrine\Common\Collections\ArrayCollection;
#[Entity]
class Article
{
#[Id, Column, GeneratedValue]
private int|null $id = null;
#[Column]
private string $title;
/** @var ArrayCollection<string, ArticleAttribute> */
#[OneToMany(targetEntity: ArticleAttribute::class, mappedBy: 'article', cascade: ['ALL'], indexBy: 'attribute')]
private Collection $attributes;
public function addAttribute(string $name, ArticleAttribute $value): void
{
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
}
}
#[Entity]
class ArticleAttribute
{
#[Id, ManyToOne(targetEntity: Article::class, inversedBy: 'attributes')]
private Article $article;
#[Id, Column]
private string $attribute;
#[Column]
private string $value;
public function __construct(string $name, string $value, Article $article)
{
$this->attribute = $name;
$this->value = $value;
$this->article = $article;
}
}
.. code-block:: annotation
<?php
namespace Application\Model;
@@ -155,16 +227,17 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
class Article
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
private int|null $id = null;
/** @Column(type="string") */
private $title;
private string $title;
/**
* @OneToMany(targetEntity="ArticleAttribute", mappedBy="article", cascade={"ALL"}, indexBy="attribute")
* @var Collection<int, ArticleAttribute>
*/
private $attributes;
private Collection $attributes;
public function addAttribute($name, $value)
public function addAttribute($name, $value): void
{
$this->attributes[$name] = new ArticleAttribute($name, $value, $this);
}
@@ -176,13 +249,13 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
class ArticleAttribute
{
/** @Id @ManyToOne(targetEntity="Article", inversedBy="attributes") */
private $article;
private Article|null $article;
/** @Id @Column(type="string") */
private $attribute;
private string $attribute;
/** @Column(type="string") */
private $value;
private string $value;
public function __construct($name, $value, $article)
{
@@ -195,14 +268,14 @@ We keep up the example of an Article with arbitrary attributes, the mapping look
.. code-block:: xml
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsi="https://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="Application\Model\ArticleAttribute">
<id name="article" association-key="true" />
<id name="attribute" type="string" />
<field name="value" type="string" />
<many-to-one field="article" target-entity="Article" inversed-by="attributes" />
@@ -237,25 +310,22 @@ One good example for this is a user-address relationship:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
/**
* @Entity
*/
#[Entity]
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
#[Id, Column, GeneratedValue]
private int|null $id = null;
}
/**
* @Entity
*/
#[Entity]
class Address
{
/** @Id @OneToOne(targetEntity="User") */
private $user;
#[Id, OneToOne(targetEntity: User::class)]
private User|null $user = null;
}
.. code-block:: yaml
@@ -288,68 +358,70 @@ of products purchased and maybe even the current price.
.. code-block:: php
<?php
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
/** @Entity */
#[Entity]
class Order
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
#[Id, Column, GeneratedValue]
private int|null $id = null;
/** @ManyToOne(targetEntity="Customer") */
private $customer;
/** @OneToMany(targetEntity="OrderItem", mappedBy="order") */
private $items;
/** @var ArrayCollection<int, OrderItem> */
#[OneToMany(targetEntity: OrderItem::class, mappedBy: 'order')]
private Collection $items;
/** @Column(type="boolean") */
private $payed = false;
/** @Column(type="boolean") */
private $shipped = false;
/** @Column(type="datetime") */
private $created;
#[Column]
private bool $paid = false;
#[Column]
private bool $shipped = false;
#[Column]
private DateTime $created;
public function __construct(Customer $customer)
{
$this->customer = $customer;
public function __construct(
#[ManyToOne(targetEntity: Customer::class)]
private Customer $customer,
) {
$this->items = new ArrayCollection();
$this->created = new \DateTime("now");
$this->created = new DateTime("now");
}
}
/** @Entity */
#[Entity]
class Product
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
#[Id, Column, GeneratedValue]
private int|null $id = null;
/** @Column(type="string") */
private $name;
#[Column]
private string $name;
/** @Column(type="decimal") */
private $currentPrice;
#[Column]
private int $currentPrice;
public function getCurrentPrice()
public function getCurrentPrice(): int
{
return $this->currentPrice;
}
}
/** @Entity */
#[Entity]
class OrderItem
{
/** @Id @ManyToOne(targetEntity="Order") */
private $order;
#[Id, ManyToOne(targetEntity: Order::class)]
private Order|null $order = null;
/** @Id @ManyToOne(targetEntity="Product") */
private $product;
#[Id, ManyToOne(targetEntity: Product::class)]
private Product|null $product = null;
/** @Column(type="integer") */
private $amount = 1;
#[Column]
private int $amount = 1;
/** @Column(type="decimal") */
private $offeredPrice;
#[Column]
private int $offeredPrice;
public function __construct(Order $order, Product $product, $amount = 1)
public function __construct(Order $order, Product $product, int $amount = 1)
{
$this->order = $order;
$this->product = $product;

View File

@@ -1,10 +1,10 @@
Separating Concerns using Embeddables
-------------------------------------
=====================================
Embeddables are classes which are not entities themselves, but are embedded
in entities and can also be queried in DQL. You'll mostly want to use them
to reduce duplication or separating concerns. Value objects such as date range
or address are the primary use case for this feature.
or address are the primary use case for this feature.
.. note::
@@ -17,7 +17,34 @@ instead of simply adding the respective columns to the ``User`` class.
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
#[Embedded(class: Address::class)]
private Address $address;
}
#[Embeddable]
class Address
{
#[Column(type: "string")]
private string $street;
#[Column(type: "string")]
private string $postalCode;
#[Column(type: "string")]
private string $city;
#[Column(type: "string")]
private string $country;
}
.. code-block:: annotation
<?php
@@ -25,23 +52,23 @@ instead of simply adding the respective columns to the ``User`` class.
class User
{
/** @Embedded(class = "Address") */
private $address;
private Address $address;
}
/** @Embeddable */
class Address
{
/** @Column(type = "string") */
private $street;
private string $street;
/** @Column(type = "string") */
private $postalCode;
private string $postalCode;
/** @Column(type = "string") */
private $city;
private string $city;
/** @Column(type = "string") */
private $country;
private string $country;
}
.. code-block:: xml
@@ -109,7 +136,18 @@ The following example shows you how to set your prefix to ``myPrefix_``:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
#[Embedded(class: Address::class, columnPrefix: "myPrefix_")]
private Address $address;
}
.. code-block:: annotation
<?php
@@ -140,7 +178,18 @@ directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML):
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
#[Embedded(class: Address::class, columnPrefix: false)]
private Address $address;
}
.. code-block:: annotation
<?php
@@ -148,9 +197,15 @@ directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML):
class User
{
/** @Embedded(class = "Address", columnPrefix = false) */
private $address;
private Address $address;
}
.. code-block:: xml
<entity name="User">
<embedded name="address" class="Address" use-column-prefix="false" />
</entity>
.. code-block:: yaml
User:
@@ -160,12 +215,6 @@ directly, set ``columnPrefix=false`` (``use-column-prefix="false"`` for XML):
class: Address
columnPrefix: false
.. code-block:: xml
<entity name="User">
<embedded name="address" class="Address" use-column-prefix="false" />
</entity>
DQL
---
@@ -176,4 +225,3 @@ as if they were declared in the ``User`` class:
.. code-block:: sql
SELECT u FROM User u WHERE u.address.city = :myCity

View File

@@ -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.
@@ -52,7 +52,20 @@ switch to extra lazy as shown in these examples:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace Doctrine\Tests\Models\CMS;
#[Entity]
class CmsGroup
{
/** @var Collection<int, CmsUser> */
#[ManyToMany(targetEntity: CmsUser::class, mappedBy: 'groups', fetch: 'EXTRA_LAZY')]
public Collection $users;
}
.. code-block:: annotation
<?php
namespace Doctrine\Tests\Models\CMS;
@@ -64,15 +77,16 @@ switch to extra lazy as shown in these examples:
{
/**
* @ManyToMany(targetEntity="CmsUser", mappedBy="groups", fetch="EXTRA_LAZY")
* @var Collection<int, CmsUser>
*/
public $users;
public Collection $users;
}
.. code-block:: xml
<?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"
xmlns:xsi="https://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">
@@ -92,4 +106,3 @@ switch to extra lazy as shown in these examples:
targetEntity: CmsUser
mappedBy: groups
fetch: EXTRA_LAZY

View File

@@ -22,5 +22,5 @@ In this workflow you would modify the database schema first and then
regenerate the PHP code to use with this schema. You need a flexible
code-generator for this task.
We spinned off a subproject, Doctrine CodeGenerator, that will fill this gap and
We spun off a subproject, Doctrine CodeGenerator, that will fill this gap and
allow you to do *Database First* development.

File diff suppressed because it is too large Load Diff

View File

@@ -5,28 +5,42 @@ There are use-cases when you'll want to sort collections when they are
retrieved from the database. In userland you do this as long as you
haven't initially saved an entity with its associations into the
database. To retrieve a sorted collection from the database you can
use the ``@OrderBy`` annotation with a collection that specifies
use the ``#[OrderBy]`` attribute with a collection that specifies
a DQL snippet that is appended to all queries with this
collection.
Additional to any ``@OneToMany`` or ``@ManyToMany`` annotation you
can specify the ``@OrderBy`` in the following way:
Additional to any ``#[OneToMany]`` or ``#[ManyToMany]`` attribute you
can specify the ``#[OrderBy]`` in the following way:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
#[Entity]
class User
{
// ...
#[ManyToMany(targetEntity: Group::class)]
#[OrderBy(["name" => "ASC"])]
private Collection $groups;
}
.. code-block:: annotation
<?php
/** @Entity **/
class User
{
// ...
/**
* @ManyToMany(targetEntity="Group")
* @OrderBy({"name" = "ASC"})
**/
private $groups;
* @var Collection<int, Group>
*/
private Collection $groups;
}
.. code-block:: xml
@@ -62,7 +76,7 @@ The DQL Snippet in OrderBy is only allowed to consist of
unqualified, unquoted field names and of an optional ASC/DESC
positional statement. Multiple Fields are separated by a comma (,).
The referenced field names have to exist on the ``targetEntity``
class of the ``@ManyToMany`` or ``@OneToMany`` annotation.
class of the ``#[ManyToMany]`` or ``#[OneToMany]`` attribute.
The semantics of this feature can be described as follows:
@@ -106,5 +120,3 @@ You can reverse the order with an explicit DQL ORDER BY:
.. code-block:: sql
SELECT u, g FROM User u JOIN u.groups g WHERE u.id = 10 ORDER BY g.name DESC, g.name ASC

View File

@@ -14,47 +14,43 @@ Suppose we have a class ExampleEntityWithOverride. This class uses trait Example
.. code-block:: php
<?php
/**
* @Entity
*
* @AttributeOverrides({
* @AttributeOverride(name="foo",
* column=@Column(
* name = "foo_overridden",
* type = "integer",
* length = 140,
* nullable = false,
* unique = false
* )
* )
* })
*
* @AssociationOverrides({
* @AssociationOverride(name="bar",
* joinColumns=@JoinColumn(
* name="example_entity_overridden_bar_id", referencedColumnName="id"
* )
* )
* })
*/
#[Entity]
#[AttributeOverrides([
new AttributeOverride('foo', [
'column' => new Column([
'name' => 'foo_overridden',
'type' => 'integer',
'length' => 140,
'nullable' => false,
'unique' => false,
]),
]),
])]
#[AssociationOverrides([
new AssociationOverride('bar', [
'joinColumns' => new JoinColumn([
'name' => 'example_entity_overridden_bar_id',
'referencedColumnName' => 'id',
]),
]),
])]
class ExampleEntityWithOverride
{
use ExampleTrait;
}
/**
* @Entity
*/
#[Entity]
class Bar
{
/** @Id @Column(type="string") */
#[Id, Column(type: 'string')]
private $id;
}
The docblock is showing metadata override of the attribute and association type. It
basically changes the names of the columns mapped for a property ``foo`` and for
the association ``bar`` which relates to Bar class shown above. Here is the trait
which has mapping metadata that is overridden by the annotation above:
which has mapping metadata that is overridden by the attribute above:
.. code-block:: php
@@ -64,19 +60,15 @@ which has mapping metadata that is overridden by the annotation above:
*/
trait ExampleTrait
{
/** @Id @Column(type="string") */
private $id;
#[Id, Column(type: 'integer')]
private int|null $id = null;
/**
* @Column(name="trait_foo", type="integer", length=100, nullable=true, unique=true)
*/
protected $foo;
#[Column(name: 'trait_foo', type: 'integer', length: 100, nullable: true, unique: true)]
protected int $foo;
/**
* @OneToOne(targetEntity="Bar", cascade={"persist", "merge"})
* @JoinColumn(name="example_trait_bar_id", referencedColumnName="id")
*/
protected $bar;
#[OneToOne(targetEntity: Bar::class, cascade: ['persist', 'merge'])]
#[JoinColumn(name: 'example_trait_bar_id', referencedColumnName: 'id')]
protected Bar|null $bar = null;
}
The case for just extending a class would be just the same but:

View File

@@ -39,3 +39,7 @@ collection. You can disable this behavior by setting the
``$fetchJoinCollection`` flag to ``false``; in that case only 2 instead of the 3 queries
described are executed. We hope to automate the detection for this in
the future.
.. note::
``$fetchJoinCollection`` flag set to ``true`` might affect results if you use aggregations in your query.

View File

@@ -23,6 +23,7 @@ Mapping Indexed Associations
You can map indexed associations by adding:
* ``indexBy`` argument to any ``#[OneToMany]`` or ``#[ManyToMany]`` attribute.
* ``indexBy`` attribute to any ``@OneToMany`` or ``@ManyToMany`` annotation.
* ``index-by`` attribute to any ``<one-to-many />`` or ``<many-to-many />`` xml element.
* ``indexBy:`` key-value pair to any association defined in ``manyToMany:`` or ``oneToMany:`` YAML mapping files.
@@ -30,7 +31,66 @@ You can map indexed associations by adding:
The code and mappings for the Market entity looks like this:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace Doctrine\Tests\Models\StockExchange;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
#[Entity]
#[Table(name: 'exchange_markets')]
class Market
{
#[Id, Column(type: 'integer'), GeneratedValue]
private int|null $id = null;
#[Column(type: 'string')]
private string $name;
/** @var Collection<string, Stock> */
#[OneToMany(targetEntity: Stock::class, mappedBy: 'market', indexBy: 'symbol')]
private Collection $stocks;
public function __construct(string $name)
{
$this->name = $name;
$this->stocks = new ArrayCollection();
}
public function getId(): int|null
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function addStock(Stock $stock): void
{
$this->stocks[$stock->getSymbol()] = $stock;
}
public function getStock(string $symbol): Stock
{
if (!isset($this->stocks[$symbol])) {
throw new \InvalidArgumentException("Symbol is not traded on this market.");
}
return $this->stocks[$symbol];
}
/** @return array<string, Stock> */
public function getStocks(): array
{
return $this->stocks->toArray();
}
}
.. code-block:: annotation
<?php
namespace Doctrine\Tests\Models\StockExchange;
@@ -47,19 +107,19 @@ The code and mappings for the Market entity looks like this:
* @Id @Column(type="integer") @GeneratedValue
* @var int
*/
private $id;
private int|null $id = null;
/**
* @Column(type="string")
* @var string
*/
private $name;
private string $name;
/**
* @OneToMany(targetEntity="Stock", mappedBy="market", indexBy="symbol")
* @var Stock[]
* @var Collection<int, Stock>
*/
private $stocks;
private Collection $stocks;
public function __construct($name)
{
@@ -67,22 +127,22 @@ The code and mappings for the Market entity looks like this:
$this->stocks = new ArrayCollection();
}
public function getId()
public function getId(): int|null
{
return $this->id;
}
public function getName()
public function getName(): string
{
return $this->name;
}
public function addStock(Stock $stock)
public function addStock(Stock $stock): void
{
$this->stocks[$stock->getSymbol()] = $stock;
}
public function getStock($symbol)
public function getStock($symbol): Stock
{
if (!isset($this->stocks[$symbol])) {
throw new \InvalidArgumentException("Symbol is not traded on this market.");
@@ -91,7 +151,8 @@ The code and mappings for the Market entity looks like this:
return $this->stocks[$symbol];
}
public function getStocks()
/** @return array<string, Stock> */
public function getStocks(): array
{
return $this->stocks->toArray();
}
@@ -101,7 +162,7 @@ The code and mappings for the Market entity looks like this:
<?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"
xmlns:xsi="https://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">
@@ -142,7 +203,38 @@ The ``Stock`` entity doesn't contain any special instructions that are new, but
here are the code and mappings for it:
.. configuration-block::
.. code-block:: php
.. code-block:: attribute
<?php
namespace Doctrine\Tests\Models\StockExchange;
#[Entity]
#[Table(name: 'exchange_stocks')]
class Stock
{
#[Id, Column(type: 'integer'), GeneratedValue]
private int|null $id = null;
#[Column(type: 'string', unique: true)]
private string $symbol;
#[ManyToOne(targetEntity: Market::class, inversedBy: 'stocks')]
private Market|null $market;
public function __construct(string $symbol, Market $market)
{
$this->symbol = $symbol;
$this->market = $market;
$market->addStock($this);
}
public function getSymbol(): string
{
return $this->symbol;
}
}
.. code-block:: annotation
<?php
namespace Doctrine\Tests\Models\StockExchange;
@@ -157,18 +249,18 @@ here are the code and mappings for it:
* @Id @GeneratedValue @Column(type="integer")
* @var int
*/
private $id;
private int|null $id = null;
/**
* @Column(type="string", unique=true)
*/
private $symbol;
private string $symbol;
/**
* @ManyToOne(targetEntity="Market", inversedBy="stocks")
* @var Market
*/
private $market;
private Market|null $market = null;
public function __construct($symbol, Market $market)
{
@@ -177,7 +269,7 @@ here are the code and mappings for it:
$market->addStock($this);
}
public function getSymbol()
public function getSymbol(): string
{
return $this->symbol;
}
@@ -187,7 +279,7 @@ here are the code and mappings for it:
<?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"
xmlns:xsi="https://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">
@@ -249,7 +341,7 @@ now query for the market:
// $em is the EntityManager
$marketId = 1;
$symbol = "AAPL";
$market = $em->find("Doctrine\Tests\Models\StockExchange\Market", $marketId);
// Access the stocks by symbol now:

View File

@@ -14,25 +14,25 @@
<xs:element name="doctrine-mapping">
<xs:complexType>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
</xs:element>
<xs:complexType name="emptyType">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="cascade-type">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="cascade-all" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-persist" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-merge" type="orm:emptyType" minOccurs="0"/>
@@ -40,7 +40,7 @@
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
@@ -66,19 +66,19 @@
</xs:simpleType>
<xs:complexType name="lifecycle-callback">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
@@ -96,34 +96,34 @@
</xs:complexType>
<xs:complexType name="named-native-query">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="result-class" type="orm:fqcn" />
<xs:attribute name="result-set-mapping" type="xs:string" />
</xs:complexType>
<xs:complexType name="named-native-queries">
<xs:sequence>
<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:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="entity-listener">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:attribute name="class" type="orm:fqcn"/>
</xs:complexType>
<xs:complexType name="entity-listeners">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="entity-listener" type="orm:entity-listener" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="column-result">
@@ -136,29 +136,29 @@
</xs:complexType>
<xs:complexType name="entity-result">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="field-result" type="orm:field-result" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:choice>
<xs:attribute name="entity-class" type="orm:fqcn" use="required" />
<xs:attribute name="discriminator-column" type="xs:string" use="optional" />
</xs:complexType>
<xs:complexType name="sql-result-set-mapping">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<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:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="sql-result-set-mappings">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="sql-result-set-mapping" type="orm:sql-result-set-mapping" minOccurs="1" maxOccurs="unbounded" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="cache">
@@ -208,28 +208,28 @@
</xs:simpleType>
<xs:complexType name="option" mixed="true">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="options">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="mapped-superclass" >
<xs:complexContent>
<xs:extension base="orm:entity">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:extension>
</xs:complexContent>
@@ -238,9 +238,9 @@
<xs:complexType name="embeddable">
<xs:complexContent>
<xs:extension base="orm:entity">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@@ -264,7 +264,6 @@
<xs:simpleType name="generator-strategy">
<xs:restriction base="xs:token">
<xs:enumeration value="NONE"/>
<xs:enumeration value="TABLE"/>
<xs:enumeration value="SEQUENCE"/>
<xs:enumeration value="IDENTITY"/>
<xs:enumeration value="AUTO"/>
@@ -289,17 +288,29 @@
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="generated-type">
<xs:restriction base="xs:token">
<xs:enumeration value="NEVER"/>
<xs:enumeration value="INSERT"/>
<xs:enumeration value="ALWAYS"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="field">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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="type" type="orm:type" default="string" />
<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" />
<xs:attribute name="insertable" type="xs:boolean" default="true" />
<xs:attribute name="updatable" type="xs:boolean" default="true" />
<xs:attribute name="generated" type="orm:generated-type" default="NEVER" />
<xs:attribute name="enum-type" type="xs:string" />
<xs:attribute name="version" type="xs:boolean" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:attribute name="precision" type="xs:integer" use="optional" />
@@ -308,97 +319,104 @@
</xs:complexType>
<xs:complexType name="embedded">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="class" type="orm:fqcn" use="required" />
<xs:attribute name="class" type="orm:fqcn" use="optional" />
<xs:attribute name="column-prefix" type="xs:string" use="optional" />
<xs:attribute name="use-column-prefix" type="xs:boolean" default="true" use="optional" />
</xs:complexType>
<xs:complexType name="discriminator-column">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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:attribute name="enum-type" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="unique-constraint">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="required"/>
<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:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="index">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="required"/>
<xs:attribute name="columns" type="xs:string" use="optional"/>
<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:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="discriminator-mapping">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="generator">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="strategy" type="orm:generator-strategy" use="optional" default="AUTO" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="id">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="generator" type="orm:generator" minOccurs="0" />
<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:sequence>
</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="type" type="orm:type" />
<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" />
@@ -406,9 +424,9 @@
</xs:complexType>
<xs:complexType name="sequence-generator">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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" />
@@ -416,9 +434,9 @@
</xs:complexType>
<xs:complexType name="custom-id-generator">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="class" type="orm:fqcn" use="required" />
</xs:complexType>
@@ -429,18 +447,25 @@
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="type" id="type">
<xs:restriction base="xs:token">
<xs:pattern value="([a-zA-Z_u01-uff][a-zA-Z0-9_u01-uff]+)|(\c+)" id="type.class.pattern">
</xs:pattern>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="inverse-join-columns">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="join-column">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional" />
<xs:attribute name="referenced-column-name" type="xs:NMTOKEN" use="optional" default="id" />
<xs:attribute name="unique" type="xs:boolean" default="false" />
@@ -451,36 +476,36 @@
</xs:complexType>
<xs:complexType name="join-columns">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="join-table">
<xs:sequence>
<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:sequence>
</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:sequence>
<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:sequence>
</xs:choice>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
<xs:complexType name="order-by-field">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</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"/>
@@ -493,14 +518,20 @@
</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:sequence>
<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:sequence>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" use="required" />
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
@@ -512,12 +543,12 @@
</xs:complexType>
<xs:complexType name="one-to-many">
<xs:sequence>
<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="order-by" type="orm:order-by" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" use="required" />
<xs:attribute name="mapped-by" type="xs:NMTOKEN" use="required" />
@@ -528,7 +559,7 @@
</xs:complexType>
<xs:complexType name="many-to-one">
<xs:sequence>
<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:choice minOccurs="0" maxOccurs="1">
@@ -537,16 +568,16 @@
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" 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">
<xs:sequence>
<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:choice minOccurs="0" maxOccurs="1">
@@ -555,9 +586,9 @@
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:choice>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
</xs:choice>
<xs:attribute name="field" type="xs:NMTOKEN" use="required" />
<xs:attribute name="target-entity" type="xs:string" use="required" />
<xs:attribute name="target-entity" type="xs:string" />
<xs:attribute name="mapped-by" type="xs:NMTOKEN" />
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
@@ -566,19 +597,19 @@
</xs:complexType>
<xs:complexType name="association-overrides">
<xs:sequence>
<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:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="association-override">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<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:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
<xs:attribute name="fetch" type="orm:fetch-type" use="optional" />
</xs:complexType>
@@ -588,30 +619,32 @@
</xs:complexType>
<xs:complexType name="attribute-overrides">
<xs:sequence>
<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:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="attribute-override">
<xs:sequence>
<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:sequence>
</xs:choice>
<xs:attribute name="name" type="xs:NMTOKEN" use="required" />
</xs:complexType>
<xs:complexType name="attribute-override-field">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="options" type="orm:options" minOccurs="0" />
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="type" type="xs:NMTOKEN" default="string" />
<xs:attribute name="column" type="xs:NMTOKEN" />
</xs:choice>
<xs:attribute name="type" type="orm:type" default="string" />
<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" />
<xs:attribute name="insertable" type="xs:boolean" default="true" />
<xs:attribute name="updateable" type="xs:boolean" default="true" />
<xs:attribute name="version" type="xs:boolean" />
<xs:attribute name="column-definition" type="xs:string" />
<xs:attribute name="precision" type="xs:integer" use="optional" />

View File

@@ -1,30 +1,20 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
declare(strict_types=1);
namespace Doctrine\ORM;
use BackedEnum;
use Countable;
use Doctrine\Common\Cache\Psr6\CacheAdapter;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Result;
use Doctrine\Deprecations\Deprecation;
use Doctrine\ORM\Cache\Exception\InvalidResultCacheDriver;
use Doctrine\ORM\Cache\Logging\CacheLogger;
use Doctrine\ORM\Cache\QueryCacheKey;
use Doctrine\ORM\Cache\TimestampCacheKey;
@@ -34,24 +24,28 @@ use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Persistence\Mapping\MappingException;
use LogicException;
use Psr\Cache\CacheItemPoolInterface;
use Traversable;
use function array_map;
use function array_shift;
use function assert;
use function count;
use function func_num_args;
use function in_array;
use function is_array;
use function is_numeric;
use function is_object;
use function is_scalar;
use function is_string;
use function iterator_count;
use function iterator_to_array;
use function ksort;
use function method_exists;
use function reset;
use function serialize;
use function sha1;
use function trigger_error;
use const E_USER_DEPRECATED;
/**
* Base contract for ORM queries. Base class for Query and NativeQuery.
@@ -87,6 +81,11 @@ abstract class AbstractQuery
*/
public const HYDRATE_SIMPLEOBJECT = 5;
/**
* Hydrates scalar column value.
*/
public const HYDRATE_SCALAR_COLUMN = 6;
/**
* The parameter map of this query.
*
@@ -98,7 +97,7 @@ abstract class AbstractQuery
/**
* The user-specified ResultSetMapping to use.
*
* @var ResultSetMapping
* @var ResultSetMapping|null
*/
protected $_resultSetMapping;
@@ -112,7 +111,7 @@ abstract class AbstractQuery
/**
* The map of query hints.
*
* @var array
* @psalm-var array<string, mixed>
*/
protected $_hints = [];
@@ -120,10 +119,11 @@ abstract class AbstractQuery
* The hydration mode.
*
* @var string|int
* @psalm-var string|AbstractQuery::HYDRATE_*
*/
protected $_hydrationMode = self::HYDRATE_OBJECT;
/** @var QueryCacheProfile */
/** @var QueryCacheProfile|null */
protected $_queryCacheProfile;
/**
@@ -133,7 +133,7 @@ abstract class AbstractQuery
*/
protected $_expireResultCache = false;
/** @var QueryCacheProfile */
/** @var QueryCacheProfile|null */
protected $_hydrationCacheProfile;
/**
@@ -157,6 +157,7 @@ abstract class AbstractQuery
* Second level query cache mode.
*
* @var int|null
* @psalm-var Cache::MODE_*|null
*/
protected $cacheMode;
@@ -188,7 +189,7 @@ abstract class AbstractQuery
*
* @param bool $cacheable
*
* @return static This query instance.
* @return $this
*/
public function setCacheable($cacheable)
{
@@ -197,9 +198,7 @@ abstract class AbstractQuery
return $this;
}
/**
* @return bool TRUE if the query results are enable for second level cache, FALSE otherwise.
*/
/** @return bool TRUE if the query results are enabled for second level cache, FALSE otherwise. */
public function isCacheable()
{
return $this->cacheable;
@@ -208,7 +207,7 @@ abstract class AbstractQuery
/**
* @param string $cacheRegion
*
* @return static This query instance.
* @return $this
*/
public function setCacheRegion($cacheRegion)
{
@@ -227,17 +226,13 @@ abstract class AbstractQuery
return $this->cacheRegion;
}
/**
* @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise.
*/
/** @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise. */
protected function isCacheEnabled()
{
return $this->cacheable && $this->hasCache;
}
/**
* @return int
*/
/** @return int */
public function getLifetime()
{
return $this->lifetime;
@@ -248,7 +243,7 @@ abstract class AbstractQuery
*
* @param int $lifetime
*
* @return static This query instance.
* @return $this
*/
public function setLifetime($lifetime)
{
@@ -258,7 +253,8 @@ abstract class AbstractQuery
}
/**
* @return int
* @return int|null
* @psalm-return Cache::MODE_*|null
*/
public function getCacheMode()
{
@@ -267,8 +263,9 @@ abstract class AbstractQuery
/**
* @param int $cacheMode
* @psalm-param Cache::MODE_* $cacheMode
*
* @return static This query instance.
* @return $this
*/
public function setCacheMode($cacheMode)
{
@@ -282,14 +279,14 @@ abstract class AbstractQuery
* The returned SQL syntax depends on the connection driver that is used
* by this query object at the time of this method call.
*
* @return string SQL query
* @return list<string>|string SQL query
*/
abstract public function getSQL();
/**
* Retrieves the associated EntityManager of this Query instance.
*
* @return EntityManager
* @return EntityManagerInterface
*/
public function getEntityManager()
{
@@ -314,6 +311,7 @@ abstract class AbstractQuery
* Get all defined parameters.
*
* @return ArrayCollection The defined query parameters.
* @psalm-return ArrayCollection<int, Parameter>
*/
public function getParameters()
{
@@ -323,9 +321,9 @@ abstract class AbstractQuery
/**
* Gets a query parameter.
*
* @param mixed $key The key (index or name) of the bound parameter.
* @param int|string $key The key (index or name) of the bound parameter.
*
* @return Query\Parameter|null The value of the bound parameter, or NULL if not available.
* @return Parameter|null The value of the bound parameter, or NULL if not available.
*/
public function getParameter($key)
{
@@ -346,14 +344,12 @@ abstract class AbstractQuery
* Sets a collection of query parameters.
*
* @param ArrayCollection|mixed[] $parameters
*
* @return static This query instance.
*
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
*
* @return $this
*/
public function setParameters($parameters)
{
// BC compatibility with 2.3-
if (is_array($parameters)) {
/** @psalm-var ArrayCollection<int, Parameter> $parameterCollection */
$parameterCollection = new ArrayCollection();
@@ -373,13 +369,13 @@ abstract class AbstractQuery
/**
* Sets a query parameter.
*
* @param string|int $key The parameter position or name.
* @param mixed $value The parameter value.
* @param string|null $type The parameter type. If specified, the given value will be run through
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
* @param string|int $key The parameter position or name.
* @param mixed $value The parameter value.
* @param string|int|null $type The parameter type. If specified, the given value will be run through
* the type conversion of this type. This is usually not needed for
* strings and numeric types.
*
* @return static This query instance.
* @return $this
*/
public function setParameter($key, $value, $type = null)
{
@@ -401,11 +397,9 @@ abstract class AbstractQuery
*
* @param mixed $value
*
* @return mixed[]|string|int|float|bool
* @return mixed
*
* @throws ORMInvalidArgumentException
*
* @psalm-return array|scalar
*/
public function processParameterValue($value)
{
@@ -427,15 +421,20 @@ abstract class AbstractQuery
return $value->name;
}
if ($value instanceof BackedEnum) {
return $value->value;
}
if (! is_object($value)) {
return $value;
}
try {
$class = ClassUtils::getClass($value);
$value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value);
if ($value === null) {
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity();
throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class);
}
} catch (MappingException | ORMMappingException $e) {
/* Silence any mapping exceptions. These can occur if the object in
@@ -487,7 +486,7 @@ abstract class AbstractQuery
/**
* Sets the ResultSetMapping that should be used for hydration.
*
* @return static This query instance.
* @return $this
*/
public function setResultSetMapping(Query\ResultSetMapping $rsm)
{
@@ -500,7 +499,7 @@ abstract class AbstractQuery
/**
* Gets the ResultSetMapping used for hydration.
*
* @return ResultSetMapping
* @return ResultSetMapping|null
*/
protected function getResultSetMapping()
{
@@ -509,10 +508,8 @@ abstract class AbstractQuery
/**
* Allows to translate entity namespaces to full qualified names.
*
* @return void
*/
private function translateNamespaces(Query\ResultSetMapping $rsm)
private function translateNamespaces(Query\ResultSetMapping $rsm): void
{
$translate = function ($alias): string {
return $this->_em->getClassMetadata($alias)->getName();
@@ -534,7 +531,7 @@ abstract class AbstractQuery
* some form of caching with UnitOfWork registration you should use
* {@see AbstractQuery::setResultCacheProfile()}.
*
* @return static This query instance.
* @return $this
*
* @example
* $lifetime = 100;
@@ -544,9 +541,34 @@ abstract class AbstractQuery
*/
public function setHydrationCacheProfile(?QueryCacheProfile $profile = null)
{
if ($profile !== null && ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getHydrationCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
if ($profile === null) {
if (func_num_args() < 1) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/9791',
'Calling %s without arguments is deprecated, pass null instead.',
__METHOD__
);
}
$this->_hydrationCacheProfile = null;
return $this;
}
// DBAL 2
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
if (! $profile->getResultCacheDriver()) {
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
if ($defaultHydrationCacheImpl) {
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultHydrationCacheImpl));
}
}
} elseif (! $profile->getResultCache()) {
$defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache();
if ($defaultHydrationCacheImpl) {
$profile = $profile->setResultCache($defaultHydrationCacheImpl);
}
}
$this->_hydrationCacheProfile = $profile;
@@ -554,9 +576,7 @@ abstract class AbstractQuery
return $this;
}
/**
* @return QueryCacheProfile
*/
/** @return QueryCacheProfile|null */
public function getHydrationCacheProfile()
{
return $this->_hydrationCacheProfile;
@@ -568,13 +588,38 @@ abstract class AbstractQuery
* If no result cache driver is set in the QueryCacheProfile, the default
* result cache driver is used from the configuration.
*
* @return static This query instance.
* @return $this
*/
public function setResultCacheProfile(?QueryCacheProfile $profile = null)
{
if ($profile !== null && ! $profile->getResultCacheDriver()) {
$resultCacheDriver = $this->_em->getConfiguration()->getResultCacheImpl();
$profile = $profile->setResultCacheDriver($resultCacheDriver);
if ($profile === null) {
if (func_num_args() < 1) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/9791',
'Calling %s without arguments is deprecated, pass null instead.',
__METHOD__
);
}
$this->_queryCacheProfile = null;
return $this;
}
// DBAL 2
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
if (! $profile->getResultCacheDriver()) {
$defaultResultCacheDriver = $this->_em->getConfiguration()->getResultCache();
if ($defaultResultCacheDriver) {
$profile = $profile->setResultCacheDriver(DoctrineProvider::wrap($defaultResultCacheDriver));
}
}
} elseif (! $profile->getResultCache()) {
$defaultResultCache = $this->_em->getConfiguration()->getResultCache();
if ($defaultResultCache) {
$profile = $profile->setResultCache($defaultResultCache);
}
}
$this->_queryCacheProfile = $profile;
@@ -585,21 +630,62 @@ abstract class AbstractQuery
/**
* Defines a cache driver to be used for caching result sets and implicitly enables caching.
*
* @deprecated Use {@see setResultCache()} instead.
*
* @param \Doctrine\Common\Cache\Cache|null $resultCacheDriver Cache driver
*
* @return static This query instance.
* @return $this
*
* @throws ORMException
* @throws InvalidResultCacheDriver
*/
public function setResultCacheDriver($resultCacheDriver = null)
{
/** @phpstan-ignore-next-line */
if ($resultCacheDriver !== null && ! ($resultCacheDriver instanceof \Doctrine\Common\Cache\Cache)) {
throw ORMException::invalidResultCacheDriver();
throw InvalidResultCacheDriver::create();
}
return $this->setResultCache($resultCacheDriver ? CacheAdapter::wrap($resultCacheDriver) : null);
}
/**
* Defines a cache driver to be used for caching result sets and implicitly enables caching.
*
* @return $this
*/
public function setResultCache(?CacheItemPoolInterface $resultCache = null)
{
if ($resultCache === null) {
if (func_num_args() < 1) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/9791',
'Calling %s without arguments is deprecated, pass null instead.',
__METHOD__
);
}
if ($this->_queryCacheProfile) {
$this->_queryCacheProfile = new QueryCacheProfile($this->_queryCacheProfile->getLifetime(), $this->_queryCacheProfile->getCacheKey());
}
return $this;
}
// DBAL 2
if (! method_exists(QueryCacheProfile::class, 'setResultCache')) {
$resultCacheDriver = DoctrineProvider::wrap($resultCache);
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
: new QueryCacheProfile(0, null, $resultCacheDriver);
return $this;
}
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setResultCacheDriver($resultCacheDriver)
: new QueryCacheProfile(0, null, $resultCacheDriver);
? $this->_queryCacheProfile->setResultCache($resultCache)
: new QueryCacheProfile(0, null, $resultCache);
return $this;
}
@@ -626,11 +712,11 @@ abstract class AbstractQuery
*
* @deprecated 2.7 Use {@see enableResultCache} and {@see disableResultCache} instead.
*
* @param bool $useCache
* @param int $lifetime
* @param string $resultCacheId
* @param bool $useCache Whether or not to cache the results of this query.
* @param int $lifetime How long the cache entry is valid, in seconds.
* @param string $resultCacheId ID to use for the cache entry.
*
* @return static This query instance.
* @return $this
*/
public function useResultCache($useCache, $lifetime = null, $resultCacheId = null)
{
@@ -646,7 +732,7 @@ abstract class AbstractQuery
* @param int|null $lifetime How long the cache entry is valid, in seconds.
* @param string|null $resultCacheId ID to use for the cache entry.
*
* @return static This query instance.
* @return $this
*/
public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null): self
{
@@ -659,7 +745,7 @@ abstract class AbstractQuery
/**
* Disables caching of the results of this query.
*
* @return static This query instance.
* @return $this
*/
public function disableResultCache(): self
{
@@ -671,17 +757,35 @@ abstract class AbstractQuery
/**
* Defines how long the result cache will be active before expire.
*
* @param int|null $lifetime How long the cache entry is valid.
* @param int|null $lifetime How long the cache entry is valid, in seconds.
*
* @return static This query instance.
* @return $this
*/
public function setResultCacheLifetime($lifetime)
{
$lifetime = $lifetime !== null ? (int) $lifetime : 0;
$lifetime = (int) $lifetime;
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setLifetime($lifetime)
: new QueryCacheProfile($lifetime, null, $this->_em->getConfiguration()->getResultCacheImpl());
if ($this->_queryCacheProfile) {
$this->_queryCacheProfile = $this->_queryCacheProfile->setLifetime($lifetime);
return $this;
}
$this->_queryCacheProfile = new QueryCacheProfile($lifetime);
$cache = $this->_em->getConfiguration()->getResultCache();
if (! $cache) {
return $this;
}
// Compatibility for DBAL 2
if (! method_exists($this->_queryCacheProfile, 'setResultCache')) {
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCacheDriver(DoctrineProvider::wrap($cache));
return $this;
}
$this->_queryCacheProfile = $this->_queryCacheProfile->setResultCache($cache);
return $this;
}
@@ -703,7 +807,7 @@ abstract class AbstractQuery
*
* @param bool $expire Whether or not to force resultset cache expiration.
*
* @return static This query instance.
* @return $this
*/
public function expireResultCache($expire = true)
{
@@ -722,9 +826,7 @@ abstract class AbstractQuery
return $this->_expireResultCache;
}
/**
* @return QueryCacheProfile
*/
/** @return QueryCacheProfile|null */
public function getQueryCacheProfile()
{
return $this->_queryCacheProfile;
@@ -733,17 +835,22 @@ abstract class AbstractQuery
/**
* Change the default fetch mode of an association for this query.
*
* $fetchMode can be one of ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY
* @param class-string $class
* @param string $assocName
* @param int $fetchMode
* @psalm-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode
*
* @param string $class
* @param string $assocName
* @param int $fetchMode
*
* @return static This query instance.
* @return $this
*/
public function setFetchMode($class, $assocName, $fetchMode)
{
if ($fetchMode !== Mapping\ClassMetadata::FETCH_EAGER) {
if (! in_array($fetchMode, [Mapping\ClassMetadata::FETCH_EAGER, Mapping\ClassMetadata::FETCH_LAZY], true)) {
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/pull/9777',
'Calling %s() with something else than ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY is deprecated.',
__METHOD__
);
$fetchMode = Mapping\ClassMetadata::FETCH_LAZY;
}
@@ -757,8 +864,9 @@ abstract class AbstractQuery
*
* @param string|int $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Query::HYDRATE_* constants.
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
*
* @return static This query instance.
* @return $this
*/
public function setHydrationMode($hydrationMode)
{
@@ -771,6 +879,7 @@ abstract class AbstractQuery
* Gets the hydration mode currently used by the query.
*
* @return string|int
* @psalm-return string|AbstractQuery::HYDRATE_*
*/
public function getHydrationMode()
{
@@ -783,6 +892,7 @@ abstract class AbstractQuery
* Alias for execute(null, $hydrationMode = HYDRATE_OBJECT).
*
* @param string|int $hydrationMode
* @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode
*
* @return mixed
*/
@@ -796,19 +906,31 @@ abstract class AbstractQuery
*
* Alias for execute(null, HYDRATE_ARRAY).
*
* @return array<int,mixed>
* @return mixed[]
*/
public function getArrayResult()
{
return $this->execute(null, self::HYDRATE_ARRAY);
}
/**
* Gets one-dimensional array of results for the query.
*
* Alias for execute(null, HYDRATE_SCALAR_COLUMN).
*
* @return mixed[]
*/
public function getSingleColumnResult()
{
return $this->execute(null, self::HYDRATE_SCALAR_COLUMN);
}
/**
* Gets the scalar results for the query.
*
* Alias for execute(null, HYDRATE_SCALAR).
*
* @return array<int,mixed>
* @return mixed[]
*/
public function getScalarResult()
{
@@ -818,7 +940,8 @@ abstract class AbstractQuery
/**
* Get exactly one result or null.
*
* @param string|int $hydrationMode
* @param string|int|null $hydrationMode
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return mixed
*
@@ -855,12 +978,13 @@ abstract class AbstractQuery
* If the result is not unique, a NonUniqueResultException is thrown.
* If there is no result, a NoResultException is thrown.
*
* @param string|int $hydrationMode
* @param string|int|null $hydrationMode
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return mixed
*
* @throws NonUniqueResultException If the query result is not unique.
* @throws NoResultException If the query returned no result and hydration mode is not HYDRATE_SINGLE_SCALAR.
* @throws NoResultException If the query returned no result.
*/
public function getSingleResult($hydrationMode = null)
{
@@ -886,7 +1010,7 @@ abstract class AbstractQuery
*
* Alias for getSingleResult(HYDRATE_SINGLE_SCALAR).
*
* @return mixed The scalar result.
* @return bool|float|int|string|null The scalar result.
*
* @throws NoResultException If the query returned no result.
* @throws NonUniqueResultException If the query result is not unique.
@@ -902,7 +1026,7 @@ abstract class AbstractQuery
* @param string $name The name of the hint.
* @param mixed $value The value of the hint.
*
* @return static This query instance.
* @return $this
*/
public function setHint($name, $value)
{
@@ -949,18 +1073,22 @@ abstract class AbstractQuery
* Executes the query and returns an IterableResult that can be used to incrementally
* iterate over the result.
*
* @deprecated
* @deprecated 2.8 Use {@see toIterable} instead. See https://github.com/doctrine/orm/issues/8463
*
* @param ArrayCollection|mixed[]|null $parameters The query parameters.
* @param string|int|null $hydrationMode The hydration mode to use.
* @psalm-param ArrayCollection<int, Parameter>|array<string, mixed>|null $parameters
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode The hydration mode to use.
*
* @return IterableResult
*/
public function iterate($parameters = null, $hydrationMode = null)
{
@trigger_error(
'Method ' . __METHOD__ . '() is deprecated and will be removed in Doctrine ORM 3.0. Use toIterable() instead.',
E_USER_DEPRECATED
Deprecation::trigger(
'doctrine/orm',
'https://github.com/doctrine/orm/issues/8463',
'Method %s() is deprecated and will be removed in Doctrine ORM 3.0. Use toIterable() instead.',
__METHOD__
);
if ($hydrationMode !== null) {
@@ -971,7 +1099,11 @@ abstract class AbstractQuery
$this->setParameters($parameters);
}
$rsm = $this->getResultSetMapping();
$rsm = $this->getResultSetMapping();
if ($rsm === null) {
throw new LogicException('Uninitialized result set mapping.');
}
$stmt = $this->_doExecute();
return $this->_em->newHydrator($this->_hydrationMode)->iterate($stmt, $rsm, $this->_hints);
@@ -981,8 +1113,10 @@ abstract class AbstractQuery
* Executes the query and returns an iterable that can be used to incrementally
* iterate over the result.
*
* @param ArrayCollection|mixed[] $parameters The query parameters.
* @param string|int|null $hydrationMode The hydration mode to use.
* @param ArrayCollection|array|mixed[] $parameters The query parameters.
* @param string|int|null $hydrationMode The hydration mode to use.
* @psalm-param ArrayCollection<int, Parameter>|mixed[] $parameters
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return iterable<mixed>
*/
@@ -1000,6 +1134,9 @@ abstract class AbstractQuery
}
$rsm = $this->getResultSetMapping();
if ($rsm === null) {
throw new LogicException('Uninitialized result set mapping.');
}
if ($rsm->isMixed && count($rsm->scalarMappings) > 0) {
throw QueryException::iterateWithMixedResultNotAllowed();
@@ -1015,6 +1152,8 @@ abstract class AbstractQuery
*
* @param ArrayCollection|mixed[]|null $parameters Query parameters.
* @param string|int|null $hydrationMode Processing mode to be used during the hydration process.
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return mixed
*/
@@ -1032,6 +1171,8 @@ abstract class AbstractQuery
*
* @param ArrayCollection|mixed[]|null $parameters
* @param string|int|null $hydrationMode
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return mixed
*/
@@ -1045,15 +1186,15 @@ abstract class AbstractQuery
$this->setParameters($parameters);
}
$setCacheEntry = static function (): void {
$setCacheEntry = static function ($data): void {
};
if ($this->_hydrationCacheProfile !== null) {
[$cacheKey, $realCacheKey] = $this->getHydrationCacheId();
$queryCacheProfile = $this->getHydrationCacheProfile();
$cache = $queryCacheProfile->getResultCacheDriver();
$result = $cache->fetch($cacheKey);
$cache = $this->getHydrationCache();
$cacheItem = $cache->getItem($cacheKey);
$result = $cacheItem->isHit() ? $cacheItem->get() : [];
if (isset($result[$realCacheKey])) {
return $result[$realCacheKey];
@@ -1063,10 +1204,8 @@ abstract class AbstractQuery
$result = [];
}
$setCacheEntry = static function ($data) use ($cache, $result, $cacheKey, $realCacheKey, $queryCacheProfile): void {
$result[$realCacheKey] = $data;
$cache->save($cacheKey, $result, $queryCacheProfile->getLifetime());
$setCacheEntry = static function ($data) use ($cache, $result, $cacheItem, $realCacheKey): void {
$cache->save($cacheItem->set($result + [$realCacheKey => $data]));
};
}
@@ -1078,7 +1217,11 @@ abstract class AbstractQuery
return $stmt;
}
$rsm = $this->getResultSetMapping();
$rsm = $this->getResultSetMapping();
if ($rsm === null) {
throw new LogicException('Uninitialized result set mapping.');
}
$data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints);
$setCacheEntry($data);
@@ -1086,17 +1229,41 @@ abstract class AbstractQuery
return $data;
}
private function getHydrationCache(): CacheItemPoolInterface
{
assert($this->_hydrationCacheProfile !== null);
// Support for DBAL 2
if (! method_exists($this->_hydrationCacheProfile, 'getResultCache')) {
$cacheDriver = $this->_hydrationCacheProfile->getResultCacheDriver();
assert($cacheDriver !== null);
return CacheAdapter::wrap($cacheDriver);
}
$cache = $this->_hydrationCacheProfile->getResultCache();
assert($cache !== null);
return $cache;
}
/**
* Load from second level cache or executes the query and put into cache.
*
* @param ArrayCollection|mixed[]|null $parameters
* @param string|int|null $hydrationMode
* @psalm-param ArrayCollection<int, Parameter>|mixed[]|null $parameters
* @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode
*
* @return mixed
*/
private function executeUsingQueryCache($parameters = null, $hydrationMode = null)
{
$rsm = $this->getResultSetMapping();
$rsm = $this->getResultSetMapping();
if ($rsm === null) {
throw new LogicException('Uninitialized result set mapping.');
}
$queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion);
$queryKey = new QueryCacheKey(
$this->getHash(),
@@ -1129,11 +1296,9 @@ abstract class AbstractQuery
return $result;
}
/**
* @return TimestampCacheKey|null
*/
private function getTimestampKey()
private function getTimestampKey(): ?TimestampCacheKey
{
assert($this->_resultSetMapping !== null);
$entityName = reset($this->_resultSetMapping->aliasMap);
if (empty($entityName)) {
@@ -1150,24 +1315,29 @@ 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()
{
$parameters = [];
$types = [];
foreach ($this->getParameters() as $parameter) {
$parameters[$parameter->getName()] = $this->processParameterValue($parameter->getValue());
$types[$parameter->getName()] = $parameter->getType();
}
$sql = $this->getSQL();
$sql = $this->getSQL();
assert(is_string($sql));
$queryCacheProfile = $this->getHydrationCacheProfile();
$hints = $this->getHints();
$hints['hydrationMode'] = $this->getHydrationMode();
ksort($hints);
assert($queryCacheProfile !== null);
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $hints);
return $queryCacheProfile->generateCacheKeys($sql, $parameters, $types, $hints);
}
/**
@@ -1175,15 +1345,17 @@ abstract class AbstractQuery
* If this is not explicitly set by the developer then a hash is automatically
* generated for you.
*
* @param string $id
* @param string|null $id
*
* @return static This query instance.
* @return $this
*/
public function setResultCacheId($id)
{
$this->_queryCacheProfile = $this->_queryCacheProfile
? $this->_queryCacheProfile->setCacheKey($id)
: new QueryCacheProfile(0, $id, $this->_em->getConfiguration()->getResultCacheImpl());
if (! $this->_queryCacheProfile) {
return $this->setResultCacheProfile(new QueryCacheProfile(0, $id));
}
$this->_queryCacheProfile = $this->_queryCacheProfile->setCacheKey($id);
return $this;
}
@@ -1193,7 +1365,7 @@ abstract class AbstractQuery
*
* @deprecated
*
* @return string
* @return string|null
*/
public function getResultCacheId()
{
@@ -1203,7 +1375,9 @@ abstract class AbstractQuery
/**
* Executes the query and returns a the resulting Statement object.
*
* @return Statement The executed database statement that holds the results.
* @return Result|int The executed database statement that holds
* the results, or an integer indicating how
* many rows were affected.
*/
abstract protected function _doExecute();
@@ -1227,7 +1401,8 @@ abstract class AbstractQuery
*/
protected function getHash()
{
$query = $this->getSQL();
$query = $this->getSQL();
assert(is_string($query));
$hints = $this->getHints();
$params = array_map(function (Parameter $parameter) {
$value = $parameter->getValue();

View File

@@ -1,22 +1,6 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
declare(strict_types=1);
namespace Doctrine\ORM;
@@ -157,6 +141,8 @@ interface Cache
* Evicts all cached query results under the given name, or default query cache if the region name is NULL.
*
* @param string|null $regionName The cache name associated to the queries being cached.
*
* @return void
*/
public function evictQueryRegion($regionName = null);

View File

@@ -1,22 +1,6 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
declare(strict_types=1);
namespace Doctrine\ORM\Cache;
@@ -26,22 +10,26 @@ namespace Doctrine\ORM\Cache;
class AssociationCacheEntry implements CacheEntry
{
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
* The entity identifier
*
* @var array<string, mixed> The entity identifier
* @readonly Public only for performance reasons, it should be considered immutable.
* @var array<string, mixed>
*/
public $identifier;
/**
* READ-ONLY: Public only for performance reasons, it should be considered immutable.
* The entity class name
*
* @var string The entity class name
* @readonly Public only for performance reasons, it should be considered immutable.
* @var string
* @psalm-var class-string
*/
public $class;
/**
* @param string $class The entity class.
* @param array<string, mixed> $identifier The entity identifier.
* @psalm-param class-string $class
*/
public function __construct($class, array $identifier)
{

View File

@@ -1,22 +1,6 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
declare(strict_types=1);
namespace Doctrine\ORM\Cache;
@@ -39,38 +23,31 @@ class CacheConfiguration
/** @var QueryCacheValidator|null */
private $queryValidator;
/**
* @return CacheFactory|null
*/
/** @return CacheFactory|null */
public function getCacheFactory()
{
return $this->cacheFactory;
}
/**
* @return void
*/
/** @return void */
public function setCacheFactory(CacheFactory $factory)
{
$this->cacheFactory = $factory;
}
/**
* @return CacheLogger|null
*/
/** @return CacheLogger|null */
public function getCacheLogger()
{
return $this->cacheLogger;
}
/** @return void */
public function setCacheLogger(CacheLogger $logger)
{
$this->cacheLogger = $logger;
}
/**
* @return RegionsConfiguration
*/
/** @return RegionsConfiguration */
public function getRegionsConfiguration()
{
if ($this->regionsConfig === null) {
@@ -80,14 +57,13 @@ class CacheConfiguration
return $this->regionsConfig;
}
/** @return void */
public function setRegionsConfiguration(RegionsConfiguration $regionsConfig)
{
$this->regionsConfig = $regionsConfig;
}
/**
* @return QueryCacheValidator
*/
/** @return QueryCacheValidator */
public function getQueryValidator()
{
if ($this->queryValidator === null) {
@@ -99,6 +75,7 @@ class CacheConfiguration
return $this->queryValidator;
}
/** @return void */
public function setQueryValidator(QueryCacheValidator $validator)
{
$this->queryValidator = $validator;

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