Initializing e.g. a readonly ID does not require loading any data from
the database. However, calling isInitialized() on the reflection of a
readonly property triggers the native lazy object initialization.
If we have a lazy property at hand, then the property cannot be initialized
already, so it is safe to skip the call.
* FIX: Handle int-backed enums for values stored as string values in MySQL ENUM columns
Related issue: doctrine#12274
* FIX: Apply coding standard changes
Related issue: doctrine#12274
* FIX: Add unit test cases
Related issue: doctrine#12274
* Update branch metadata
3.6.0 has been released. As a consequence:
- 3.7.x is the next minor branch;
- 3.6.x is the current branch;
- 3.5.x is no longer maintained.
* doc: drop old releases
We should reduce the number of versions we have, so let's remove docs
for versions that have less than 2k downloads per day.
Right now, the ORM handles the conversion of strings that happen to be
default expressions for date, time and datetime columns into the
corresponding value objects.
Let us allow users to specify these value objects directly, and
deprecate relying on the aforementioned conversion.
I think #11289 did not completely fix problem for eager fetch.
Change in that PR checked if primary key of target class is composite but that does not matter when loading collection by foreign key.
It should check if foreign key on target class is composite.
Fix from that PR did not work for me because i had entity with regular autogenerated id (single column), but foreign key referenced entity with composite primary key, like SecondLevelWithoutCompositePrimaryKey in this PR.
Checking if foreign key is composite fixed the problem for me.
This adds the membervariable hints to the QueryBuilder to enable setting hints
that will be applied to the query when it is created. This can help trigger
custom walker classes when the query is not adressable driectly e.g. in
Symfony Form Extensions where the quer_builder normalizer is handed the querybuilder
directly. Also see #11849
The feature mirrors the hint feature from the Query class.
This also adds tests for the hints in the QueryBuilder to ensure that those are added
correctly and applied to the query itself on creation
This addresses the deprecation introduced in
https://github.com/doctrine/dbal/pull/7195
A follow-up should be to deprecate not using these value objects in
field mappings, so that we do not just reproduce the same checks that
the DBAL wants to remove.
DQL arbitrary joins are semantically equivalent to SQL joins, so using
the same keyword reduces confusion. It also means that in next major
version, the WITH keyword will only be about applying adhoc filtering on
relations instead of having 2 responsibilities.
* Do not eagerly set metadata from ResolveTargetEntityListener
When using the `ResolveTargetEntityListener` to substitute `targetEntities` in association mappings, do not eagerly put the resolved (target) entity into the class metadata cache under the class name of the original entity.
#### Motivation
I have a library that wants to distribute a MappedSuperclass as the base for some functionality. It will be necessary that clients using the library will extend the MappedSuperclass to fill in some blanks, creating the first real `#[Entity]` instance of it.
This client-provided entity will be the primary means of working with the class. Thus, I was following the [note in the documentation](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/reference/inheritance-mapping.html#mapped-superclasses:~:text=It%20is%2C%20however) and using the `ResolveTargetEntityListener` to declare that whenever an association refers to that mapped superclass, the particular entity class shall be used instead.
> One-To-Many associations are not generally possible on a mapped superclass, since they require the "many" side to hold the foreign key.
> It is, however, possible to use the [ResolveTargetEntityListener](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/cookbook/resolve-target-entity-listener.html) to replace references to a mapped superclass with an entity class at runtime. As long as there is only one entity subclass inheriting from the mapped superclass and all references to the mapped superclass are resolved to that entity class at runtime, the mapped superclass can use One-To-Many associations and be named as the targetEntity on the owning sides.
#### Changes made
The `ResolveTargetEntityListener` primarily does what its name suggests: For newly loaded class metadata, it inspects all associations declared and replaces the `targetEntity` with new (resolved) values.
But additionally, when a loaded class is the target of such a resolution, it would also put the class metadata into the cache under the name of the original entity.
I think that extra step is wrong, and this PR removes it. It had the side effect that when other classes extending the MappedSuperclass were loaded _after_ the resolve target class has been seen for the first time, the metadata for those classes would not inherit from the mapped superclass anymore, but from the target entity class instead. In my real-life use case, this causes weird mapping errors down the road; as of ^3.0, it would throw a mapping exception asking to configure inheritance mapping. But note that there would be no inheritance between the two entity classes at all.
#### More background
The documentation [describes the use of `ResolveTargetEntityListener`](https://www.doctrine-project.org/projects/doctrine-orm/en/3.5/cookbook/resolve-target-entity-listener.html) with an interface that is resolved to an entity class. For an interface, adding the extra metadata does not make a difference, since it never interferes with actual entity or mapped superclasses.
The initial idea of adding a copy of the entity class metadata under the interface name came from commit
9c7f3f2747 in #385. The goal was to make it possible to also find entities by interface names, like so:
```
$em->find('Foo\BarBundle\Entity\PersonInterface', 1);
```
It then [turned out that this only worked when the resolution had already been applied](https://github.com/doctrine/orm/pull/385#issuecomment-6658893). So, the new `onClassMetadataNotFound` event was added and the resolution map would be checked in that case as well (#1181). The inital code stayed in place, possibly giving a small performance gain.
In my real-world use case and the test case I added in this PR, the associations are even self-referencing. That should not really be necessary for the problem to surface. I decided to keep it this way to show that the `targetEntity` need not be an interface after all, and that a MappedSuperclass can be used in the same way.
This PR fixes the `Criteria` matching API for `IN` and `NIN` conditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly.
Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level.
Memory-based collections (`ArrayCollection`s or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results.
But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison.
One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a [limited list of types](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion) is supported.
I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like `?, ?, ?`) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them.
Previous stalled attempt to fix this was in #11897.
The order of results is not guaranteed unless we do so, and the test can
fail in some cases:
There was 1 failure:
1) Doctrine\Tests\ORM\Functional\QueryTest::testToIterableWithMixedResultArbitraryJoinsScalars
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Doctrine 2'
+'lala 2'
/home/runner/work/orm/orm/tests/Tests/ORM/Functional/QueryTest.php:481
* 3.5.x:
Fix missing import
Remove calls to getMockForAbstractClass() (#12003)
Upgrade to doctrine/coding-standard 14
Bump doctrine/.github from 7.3.0 to 8.0.0
* 3.5.x:
Add a CI job that fails on deprecations (#12188)
use the empty string instead of null as an array offset (#12181)
do not call setAccessible() on PHP >= 8.1 (#12182)
Fix docs on final entities (#12176)
Remove Database and Model First chapters that said little of value.
Switch to IgnoreDeprecations
docs: consistent PostgreSQL's name case
docs: generation strategies differences between DBAL 3 and 4
Check extra condition to decide if a test was skipped
Use PHPUnit 11 when possible
Migrate away from annotations in tests
Migrate away from assertStringNotMatchesFormat()
Migrate to willReturn()
Migrate away from getMockForAbstractClass()
Fix `IN`/`NOT IN` expression handling and support enums when matching on to-many-collections
In the scope of https://github.com/doctrine/persistence/pull/433
(available from `doctrine/persistence` >= 4.1) there was added
`ColocatedMappingDriver::$classLocator` (`ClassLocator`) property,
which allows passing any instance of `ClassLocator` for the mapping
driver to use. This commit integrates those changes into `AttributeDriver`.
Since `doctrine/orm` maintains the support for `doctrine/persistence`
of older versions, tests ensure that `ClassLocator` actually exists.
The old paths' behaviour can be adapted into the new by passing
`FileClassLocator` into `AttributeDriver`
(see `FileClassLocator::createFromDirectories($directoryPaths)`).
It seems that this could happen with PHPUnit 10, then tearDown() would
crash when calling `clear()` on null, but then PHPUnit 10 did not show
that exception.
Using a nullable column that references another table as part of a
primary key makes no sense, and is ignored by DBAL. Let us ignore it at
the ORM level.
Fix JoinedSubclassPersister as BasicEntityPersister was already fixed in GH-10735.
The fix can be verified by modifying UnitOfWork to execute `BasicEntityPersister::executeInserts()` for multiple entities at once for the same entity class/persister instance - https://github.com/doctrine/orm/blob/2.20.3/src/UnitOfWork.php#L1186 - then reproducible on `Doctrine\Tests\ORM\Functional\Ticket\GH10531Test::testInserts` test.
As extending/modifying UnitOfWork in tests in not easily possible, I submit this fix for v2.x without a test.
That test was testing too many thing and not really making it clear what
the expected output was, given some output. Instead, let us create 2
tests, each pertaining to the class under test.
In aa141bf001, I wrongly assumed that
$tableName would never contain a dot as I was not able to write a test
that caused that to happen.
The secret recipe appears to be to define a schema and to quote the
table name.
To fix it for the table name, I am calling quoteSingleIdentifier()
before doing the concatenation between schema name and table name.
To fix it for the sequence name, which seems only useful when using DBAL
3 for some reason, I reuse some of the logic of the deprecated method.
Fixes#12041
When the persister is extended to do a multi update, the caching is not
wanted. The impact is minimal as the CPU/time overhead per query is
much bigger and the prepared statement is not cached anyway.
This should fix the build. Maybe some of the reported issues can be
addressed, but if that is the case, it should probably be done on the
next minor branch.
This fixes a dangerous bug where LIMIT is silently ignored in DELETE
operations, potentially causing developers to delete all rows instead
of just the intended subset. The setMaxResults() method would be
silently omitted from the final query, making operations like
delete last entry accidentally delete entire tables.
Add proper handling for binary primary key parameter types that were
previously causing runtime exceptions. The existing parameter type
switch statement was missing a case for binary types, leading to
unhandled scenarios when working with binary primary keys.
This ensures consistent parameter type handling across all supported
primary key data types in the ORM.
That method has been deprecated for almost 15 years, in
85d40847ac.
On top of that I'm adding a deprecation for something related that was
scheduled for deprecation at in the same commit.
These tests and benchmarks are still relevant with lazy objects.
I am not setting up an extra job to test phpbench without native lazy
objects. Instead, I'm bumping the PHP version to 8.4 so that native lazy
objects are in use.
Using the VarExporter Hydrator to assign default values of properties when marking an entity as initialized is needed only when using var-exporter proxies.
For lazy objects, this behavior is already provided by `ReflectionClass::markLazyObjectAsInitialized`
Currently we have ORMSetup::create*Configuration methods with a
$proxyDir argument that is used to configure the proxy directory, but
also as a seed for generating a namespace for cache systems.
Since these methods could be used with named arguments, renaming the
argument is not really an option and we need separate methods.
Adds a new option to Column mapping to add indexes to class fields
directly instead of having to use the Index() class attribute.
This allows users to define indexes in traits
where access to the class isn't available.
Fixes#11982
This reverts commit 12c721f528.
This feature introduces several issues:
- It adds alias.*, which is a first, for instance you cannot do
SELECT u.* FROM User u
- If introduces coupling between property order in mapping fields and
the result.
When using native lazy objects, it should be possible to omit these
arguments, hence the default value.
Also, when using native lazy objects, one should not have to configure
the corresponding Configuration attributes, which means
EntityManager__construct() should be able to pass null to this class,
hence the nullability.
Fixes#11997
In 3.0.0, it is no longer possible to disable lazy ghost objects, and
likewise, it is no longer possible to disable rejecting id collisions in
the identity map, so let us deprecate the related methods.
I was supposed to do this in 3.1.0.
The `SequenceGenerator` is potentially used for PostgreSQL table auto-generated fields, but
the `SequenceGenerator` is not a **POST**-insert generator.
Because the `SequenceGenerator` is used in the middle of `INSERT` operations performed
by persisters, we cannot rely on it in batching operations: disabling it, so we get a green
test suite on PostgreSQL.
This change makes `GH10531Test` pass on PostgreSQL: see #10531
This logic also brings a minor benefit in reducing the number of times `ListenersInvoker#getSubscribedSystems`
is queried.
TODOs:
* [ ] integration test this - it is expected to reduce the number of `EntityPersister#executeInserts()` calls
* [ ] refactor this by creating a new `@internal` class for the batch, and perhaps batch via a generator
* [ ] reduce amount of repeated `getClassMetadata()` calls
* [ ] reduce overall size of `UnitOfWork` code, instead of increasing it
This command's purpose is to provide structured data, except for a call
to caution() that warns the user in case they do not have any mapped
entities or they have errors.
Symfony 7.3 is not available to all of our users, so we cannot switch to
native lazy objects, which require a PHP version higher than the lowest
PHP version we support.
In f256d996cc, I did a global move to
stderr for notifications, and went a bit overboard for
MappingDescribeCommand, which purpose is to output a description.
For some reason, it does not appear to work when nested inside a
code-block directive. Anyway, if you specify the language attribute, you
get markup identical to what you obtain when using code-block and
literalinclude, so this wrapping seems unneeded.
PostLoad listeners might initialize values for transient properties, so
the proxy should not skip initialization when using transient
properties.
Co-authored-by: Nicolas Grekas <nicolas.grekas@gmail.com>
The old proxy implementation of doctrine/common was triggered by public
methods rather than access to properties (making public properties
unsupported in entities), so tests could use public instance properties
to track the state of postLoad lifecycle callbacks without triggering
the proxy initialization when reading that state (which then changes the
state of triggering the postLoad callback).
As the new proxy implementation hooks into properties instead, the tests
now use a static method (ensuring it is reset properly before loading
the instance for which we care about the tracking) instead of an
instance property.
This fixes that using a `Criteria` with an `IN` or `NIN` expression on a to-many collection currently leads to an SQL error (#6173). The `ManyToMany` persister needs to know about the slightly different SQL syntax for `[NOT] IN ()`.
In the case of `[NOT] IN` expressions, the value will be an array, which also required me to change (I guess "fix") the parameter type handling. I have pulled the necessary code from the `BasicEntityPersister` and placed it as static helper methods in `PersisterHelper`.
This is somewhat inspired by #11516, which aims at fixing #11481: By re-using the parameter type handling code, it also fixes using backed enums in `EQ`, `IN` and `NIN` expressions within `Criteria` when `matching()` on one-to-many and many-to-many collections.
* Introduce PHP 8.4 lazy proxy/ghost API.
* Call setRawValueWithoutLazyInitialization for support with lazy proxy.
* Refactorings
* Revert test change partially and skip with lazy objects.
* Houskeeping: phpcs
* Run with ENABLE_LAZY_PROXY=1 in php 8.4 matrix.
* Fix ci
* Transient properties are not skipping lazy initialization anymore, to expensive and could lead to errors. Adjust lifecycle test that uses transient properittes for assertions.
* Restore behavior preventing property hook use in 8.4 in unsupported coditions
* Add \ReflectionClass::SKIP_INITIALIZATION_ON_SERIALIZE
Co-authored-by: Nicolas Grekas <nicolas.grekas@gmail.com>
* Rename isNativeLazyObjectsEnabled/enableNativeLazyObjects.
* Housekeeping: phpcs
* Update advanced-configuration docs and make proxy config variables not required anymore with native lazy objects.
* Move code around
* Apply suggestions from code review
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
* Pick suggestions
---------
Co-authored-by: Nicolas Grekas <nicolas.grekas@gmail.com>
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
The dev configuration and CI configuration should not diverge this much.
I do not think the current situation was intended. A difference that
remains after my changes is the bootstrap file, which in dev seems aimed
at helping contributors setup their environment.
If scheduleForInsert was called in prePersist hook already, then persistNew need to check this case first, otherwise a ORMInvalidArgumentException will be thrown
This fixes a bug that arises when using Pagination and an entity relation is mapped with fetch-mode EAGER but setFetchMode LAZY (or anything that is not EAGER) has been used on the query. If the query use WITH condition, an exception is incorrectly raised (Associations with fetch-mode=EAGER may not be using WITH conditions).
The class LimitSubqueryOutputWalker clones the query, but not its parameters and hints, so the generated subquery does not know that fetch-mode has been overridden.
Fixes#11741
The bug related (#11694) and fixed mapping of sql column alias to field in entity (#11783) and
invalidate cache [cache/persisted/entity|cache/persisted/collection] when sql filter changes
* 2.20.x:
Introduce testNotListedValueInEnumArray
Fix documentation for JoinColumn nullable (#11798)
Ignore deprecations from doctrine/common
Fix fields of transient classes being considered duplicate with `reportFieldsWhereDeclared`
just one bracket (...) gives
Exception : [Doctrine\ORM\Query\QueryException] [Syntax Error] line 0, col xx: Error: Expected Doctrine\ORM\Query\Lexer::T_IDENTIFIER, got '('
Previously, when using a custom naming strategy, explicitly declaring a JoinColumn required specifying the referencedColumnName always as it would default to id no matter the naming strategy. This PR changes it to be determines correctly.
Ref #9558
When there are no conflicts between branches, we create pull requests
where the head branch is a branch on the origin repository. That branch
points to a commit that should already have coverage information
provided by the build that happens after merging a regular pull request.
The thing is, coverage information provided by builds that happen before
merging a pull request are associated with the commit of the head
repository. This means that when merging up 1.2 into 1.3, the build
produces coverage information that is the result of a merge between 1.2
and 1.3, and associates it with 1.2, although it is run on with a
codebase that is much closer to 1.3 (and is in fact supposed to become
1.3 after the merge).
This means that when we create a merge up PR from 1.2 to anything else,
the coverage information is going to be wrong until a PR targeting 1.2
gets merged.
I do not think we need coverage about conflictless merge up PRs more
than we need accurate numbers, so I propose we disable the upload for
those instead of, say, trying to associate them with the temporary merge
commit.
CachedPersisterContext::$selectJoinSql should be clear or regenerated when sqlFilter changed
The problem reproduce when in use fetch=EAGER and use additional sql filter on this property
I think it would be great to use literalinclude for big code snippets,
because our IDEs could warn us about issues, and it would be easily to
showcase our coding standard. Before we do that though, let us validate
that it renders as expected. I have picked a complex example where we
have a configuration block.
* Add a test covering the #11112 issue
* Add new OutputWalker and SqlFinalizer interfaces
* Add a SingleSelectSqlFinalizer that can take care of adding offset/limit as well as locking mode statements to a given SQL query.
Add a FinalizedSelectExecutor that executes given, finalized SQL statements.
* In SqlWalker, split SQL query generation into the two parts that shall happen before and after the finalization phase.
Move the part that generates "pre-finalization" SQL into a dedicated method. Use a side channel in SingleSelectSqlFinalizer to access the "finalization" logic and avoid duplication.
* Fix CS violations
* Skip the GH11112 test while applying refactorings
* Avoid a Psalm complaint due to invalid (?) docblock syntax
* Establish alternate code path - queries can obtain the sql executor through the finalizer, parser knows about output walkers yielding finalizers
* Remove a possibly premature comment
* Re-enable the #11112 test
* Fix CS
* Make RootTypeWalker inherit from SqlOutputWalker so it becomes finalizer-aware
* Update QueryCacheTest, since first/max results no longer need extra cache entries
* Fix ParserResultSerializationTest by forcing the parser to produce a ParserResult of the old kind (with the executor already constructed)
* Fix WhereInWalkerTest
* Update lib/Doctrine/ORM/Query/Exec/PreparedExecutorFinalizer.php
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
* Fix tests
* Fix a Psalm complaint
* Fix a test
* Fix CS
* Make the NullSqlWalker an instance of SqlOutputWalker
* Avoid multiple cache entries caused by LimitSubqueryOutputWalker
* Fix Psalm complaints
* Fix static analysis complaints
* Remove experimental code that I committed accidentally
* Remove unnecessary baseline entry
* Make AddUnknownQueryComponentWalker subclass SqlOutputWalker
That way, we have no remaining classes in the codebase subclassing SqlWalker but not SqlOutputWalker
* Use more expressive exception classes
* Add a deprecation message
* Move SqlExecutor creation to ParserResult, to minimize public methods available on it
* Avoid keeping the SqlExecutor in the Query, since it must be generated just in time (e. g. in case Query parameters change)
* Address PHPStan complaints
* Fix tests
* Small refactorings
* Add an upgrade notice
* Small refactorings
* Update the Psalm baseline
* Add a missing namespace import
* Update Psalm baseline
* Fix CS
* Fix Psalm baseline
---------
Co-authored-by: Grégoire Paris <postmaster@greg0ire.fr>
It maybe happen that the SQL COMMIT statement is successful, but then
something goes wrong. In that kind of case, you do not want to attempt a
rollback.
This was implemented in UnitOfWork::commit(), but for some reason not in
the similar EntityManager methods.
We use this method only from within one of our own test cases, and I don't see how it would be useful to anybody else outside – it has to be called on the `Parser` instance which exists internally in the `Query` only.
Deprecating and removing it in 3.x allows for a slight simplification in the `Parser` there, since we do no longer need the field (it can be a local variable).
People that might have experimented with property hooks while still
using ORM < 2.20.0 need to know that they need to remove their
experiment or upgrade to a version that explicitly supports them.
* 2.19.x:
Make nullable parameters explicit in generated entities (#11625)
Update attributes-reference.rst
Bump doctrine/.github from 5.0.1 to 5.1.0 (#11616)
Move orphan metadata to where it belongs
PHPStan 1.12 (#11585)
When adding the same lifecycle event callback to two or more lifecycle events, the generator will create a stub for each event resulting in fatal 'Cannot redeclare' errors. That is, only if the callback name contains uppercase letters.
If the source entity for an inverse (non-owning) 1-1 relationship is
identified by an association then the identifying association may not
be set when an inverse one-to-one association is resolved. This means
that no data is available in the entity to resolve the needed column
value for the join query.
The original entity data can be retrieved from the unit of work and
is used as a fallback to populate the query condition.
Fixes#11108
single-inheritence entity parent as targetEntity.
When using the parent entity for a single-inheritence table as the
targetEntity for a property, the discriminator value should be all
of the values in the discriminator map.
OneToManyPersister::deleteEntityCollection has been amended to
reflect this.
This change makes CountWalker use COUNT(*) instead of
COUNT(tbl.id), when the user declared that their query
does not need to use (SELECT) DISTINCT, which is
commonly the case when there are no JOINs in the query,
or when the JOINs are only *ToOne.
Research showed that COUNT(*) allows databases to use
index(-only) scans more eagerly from any of the
indexed columns, especially when the query is using
a WHERE-condition that filters on an indexed column.
The Query class (used for DQL queries) takes care of using the value and
type as is when a type was specified for a parameter instead of going
through the default processing of values.
The NativeQuery class was missing the equivalent check, making the
custom type work only if the default processing of values does not
convert the value to a different one.
When a ManyToOne attribute is encountered on an Embeddable class, the exception message reads "Attribute "Doctrine\ORM\Mapping\OneToMany" on embeddable [class] is not allowed.". This should be "Doctrine\ORM\Mapping\ManyToOne" on embeddable [class] is not allowed.".
When using ghost objects, the method was leaking a `static` return type due to the way it was implemented, which is incompatible with the native return type that will be added in doctrine/persistence v4.
Remove redundant condition to check if target class contains foreign
identifier in order to allow fetching a null for relations with
composite keys, when part of the key value is null.
* 2.19.x:
Fix OneToManyPersister::deleteEntityCollection missing discriminator column/value. (GH-11500)
Skip joined entity creation for empty relation (#10889)
ci: maintained and stable mariadb version (11.4 current lts) (#11490)
fix(docs): use string value in `addAttribute`
Replace assertion with exception (#11489)
Use ramsey/composer-install in PHPBench workflow
update EntityManager#transactional to EntityManager#wrapInTransaction
Fix cloning entities
Consider usage of setFetchMode when checking for simultaneous usage of fetch-mode EAGER and WITH condition.
* 2.19.x:
Fix OneToManyPersister::deleteEntityCollection missing discriminator column/value. (GH-11500)
Skip joined entity creation for empty relation (#10889)
ci: maintained and stable mariadb version (11.4 current lts) (#11490)
fix(docs): use string value in `addAttribute`
Replace assertion with exception (#11489)
Use ramsey/composer-install in PHPBench workflow
update EntityManager#transactional to EntityManager#wrapInTransaction
Fix cloning entities
Consider usage of setFetchMode when checking for simultaneous usage of fetch-mode EAGER and WITH condition.
This fixes a bug that arises when an entity relation is mapped with
fetch-mode EAGER but setFetchMode LAZY (or anything that is not EAGER)
has been used on the query. If the query use WITH condition, an
exception is incorrectly raised (Associations with fetch-mode=EAGER may
not be using WITH conditions).
Fixes#11128
Co-Authored-By: Albert Prat <albert.prat@interactiu.cat>
* 3.1.x:
Fix failed merge (#11464)
Test with actual lock modes (#11465)
Backport test for Query::setLockMode() (#11463)
Fix return type of Query::getLockMode() (#11462)
* 3.1.x:
Using an integer as discriminator value with ORM v3
Using an integer as discriminator value with ORM v3
Bump ramsey/composer-install from 2 to 3 (#11442)
Use ramsey/composer-install in PHPBench workflow (#11444)
Bump doctrine/.github from 3.0.0 to 5.0.1
Upgrade codecov/codecov-action
Setup Dependabot
This fixes a bug that occurred when configuring integers as discriminator values and using DQL instanceOf function in the queries. Doctrine throws a type error whenever the application generates these queries.
This fixes a bug that occurred when configuring integers as discriminator values. Doctrine throws a type error whenever the application generates queries.
Targeting 2.19.x, since we want the updates to bubble up. Since
Dependabot has had no effect on doctrine/dbal yet, I suppose that means
that "dependabot.yml" must be present on the default branch.
If the entity gets reloaded from database before the deletions are
executed UnitOfWork needs to be able to return the original instance in
REMOVED state.
Changed capitalized column names to lowercase for consistency. Other occurances of column names mentioned as lowercase several times at this same page.
See https://github.com/doctrine/collections/issues/368 for the same
issue in doctrine/collections which has been fixed there.
The issue happens when using ->contains(). Running psalm emits
> InvalidArgument - Argument 1 of Doctrine\ORM\PersistentCollection::contains
> expects
> TMaybeContained:fn-doctrine\common\collections\readablecollection::contains
> as mixed, but … provided.
Solution: we should either not define @template TMaybeContained or
re-define the complete psalm docblock from ReadableCollection.
Repairing the docblock necessitates an update to the psalm baseline:
one "known issue" is no longer an issue and thus removed.
* 3.1.x:
Adjust PHPBench mocks
Set column length explicitly (#11393)
Add missing import
Remove unused variable (#11391)
Fixed proxy initialization for EnumReflectionProperty
Remove older versions from the docs (#11383)
[Documentation] Removing "Doctrine Mapping Types" ... (#11384)
[GH-11185] Bugfix: do not use collection batch loading for indexBy assocations. (#11380)
Improve lazy ghost performance by avoiding self-referencing closure. (#11376)
Remove outdated git metadata files (#11362)
Switch join columns around, otherwise index doesnt match
Key on fk
Fix entities and mapping.
Minor code style fix in AbstractRemoteControl
Do not schedule batch loading for target classes with composite identifier.
Cleanup tests not to use model sets.
provides a test case for github issue 11154
The properties `indexes` and `uniqueConstraints` were used by the
`AnnotationDriver` but were never implemented for the `AttributeDriver`.
Since the `AnnotationDriver` doesn't exist anymore these can become
deprecated and will then be removed afterwards.
Change `PESSIMISTIC_READ` to `PESSIMISTIC_WRITE`. Otherwise, the solution to the race condition at the bottom of the article would allow concurrent reads, which would not solve the presented race condition problem.
* Fix loading SchemaTool::getSchemaFromMetadata() uniqueConstraint without a name
Fixes a type miss-match exception when reading a UniqueConstraint defined on an Entity which doesn't have a predefined name.
* Fix deprecation on DBAL 3
---------
Co-authored-by: Alexander M. Turek <me@derrabus.de>
* Use class from persistence package
It is meant to remove duplication between the ORM and the ODM.
* Update UPGRADE.md
Co-authored-by: Steve Todd <stodd@mashbo.com>
---------
Co-authored-by: Alexander M. Turek <me@derrabus.de>
Co-authored-by: Steve Todd <stodd@mashbo.com>
`getAssociationMappedByTargetField()` returns `null` when called with
the owning side of an association.
This is undocumented and wrong because the phpdoc advertises a string as
a return type.
Instead, callers should ensure they are calling that method with an
inverse side.
Closes#11250
The phpdoc comment for the return type of
ClassMetadata::fullyQualifiedClassName() says that the return type will
be null if the input value is null. I have made it more precise by
using "if and only if", made the null check more strict and translated
that into template annotations. Also, since we say we return a
class-string, I've asserted that.
* 3.0.x:
Test different ways of settings query parameters
Be less restrictive in DiscriminatorColumnMapping phpdoc (#11226)
Allow (Array)ParameterType in QueryBuilder
After 2.17 (some?) EAGER fetched OneToMany associations stopped working, if they have multiple join columns. Loads for these associations will trigger a `MessingPositionalParameter` exception "Positional parameter at index 1 does not have a bound value".
This test case should reproduce this issue, so it can be fixed.
The comment above mentions that on some platforms, it might return
false, and this is why there is a check in the first place. Let us do
exactly what is mentioned in the comment.
* 3.0.x:
Remove broken assertion from DateAddFunction and DateSubFunction (#11243)
Remove unused trait
[Documentation] Adding link to Postgres upgrade article (#11257)
fix: support array-type arg in QB variadic calls (#11242)
* 2.19.x:
Fix Static Analysis folder reference (#11281)
docs: recommend safer way to disable logging (#11269)
Remove unused baseline entries
Treat '0' as a legitimate trim char
Add type field mapper documentation to the sidebar
Mark document as orphan
Use correction sectionauthor syntax
Make docs valid according to guides 0.3.3 (#11252)
* 3.0.x:
Revert "Merge pull request #11229 from greg0ire/add-columns"
Add columns for 3.1.x and 4.0x
Update version ORM from 2 to 3 in docs (#11221)
Clean up outdated sentence (#11224)
Update README.md
Point link to correct upgrade guide (#11220)
Ignore subclasses without discriminatorValue when generating discriminator column condition SQL (#11200)
Update branches in README
* Add TokenType class
Co-authored-by: Alexander M. Turek <me@derrabus.de>
* Deprecated Lexer constants in favour of TokenType
* Replace all Lexer::T_ occurrences with TokenType::T_
* Add upgrade note
* Fixed import Lexer => TokenType
* Fixed deprecation phpdoc
* Replaced int value with matching constant of TokenType
* Update src/Query/Lexer.php
---------
Co-authored-by: Alexander M. Turek <me@derrabus.de>
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.
See the General notes to upgrading to 3.x versions above.
## BC BREAK: Calling `ClassMetadata::getAssociationMappedByTargetField()` with the owning side of an association now throws an exception
Previously, calling
@@ -25,6 +346,9 @@ so `$targetEntity` is a first argument now. This change affects only non-named a
When using the `AUTO` strategy to let Doctrine determine the identity generation mechanism for
an entity, and when using `doctrine/dbal` 4, PostgreSQL now uses `IDENTITY`
instead of `SEQUENCE` or `SERIAL`.
There are three ways to handle this change.
* If you want to upgrade your existing tables to identity columns, you will need to follow [migration to identity columns on PostgreSQL](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.0/how-to/postgresql-identity-migration.html)
* If you want to keep using SQL sequences, you need to configure the ORM this way:
@@ -490,7 +490,7 @@ where you can generate an arbitrary join with the following syntax:
..code-block::php
<?php
$query=$em->createQuery('SELECT u FROM User u JOIN Banlist b WITH u.email = b.email');
$query=$em->createQuery('SELECT u FROM User u JOIN Banlist b ON u.email = b.email');
With an arbitrary join the result differs from the joins using a mapped property.
The result of an arbitrary join is an one dimensional array with a mix of the entity from the ``SELECT``
@@ -513,16 +513,46 @@ it loads all the related ``Banlist`` objects corresponding to this ``User``. Thi
when the DQL is switched to an arbitrary join.
..note::
The differences between WHERE, WITH and HAVING clauses may be
The differences between WHERE, WITH, ON and HAVING clauses may be
confusing.
- WHERE is applied to the results of an entire query
-WITH is applied to a join as an additional condition. For
arbitrary joins (SELECT f, b FROM Foo f, Bar b WITH f.id = b.id)
the WITH is required, even if it is 1 = 1
-ON is applied to arbitrary joins as the join condition. For
arbitrary joins (SELECT f, b FROM Foo f, Bar b ON f.id = b.id)
the ON is required, even if it is 1 = 1. WITH is also
supported as alternative keyword for that case for BC reasons.
- WITH is applied to an association join as an additional condition.
- HAVING is applied to the results of a query after
aggregation (GROUP BY)
Partial Hydration Syntax
^^^^^^^^^^^^^^^^^^^^^^^^
By default when you run a DQL query in Doctrine and select only a
subset of the fields for a given entity, you do not receive objects
back. Instead, you receive only arrays as a flat rectangular result
set, similar to how you would if you were just using SQL directly
and joining some data.
If you want to select partial objects or fields in array hydration you can use the ``partial``
DQL keyword:
..code-block::php
<?php
$query=$em->createQuery('SELECT partial u.{id, username} FROM CmsUser u');
$users=$query->getResult();// array of partially loaded CmsUser objects
You can use the partial syntax when joining as well:
..code-block::php
<?php
$query=$em->createQuery('SELECT partial u.{id, username}, partial a.{id, name} FROM CmsUser u JOIN u.articles a');
$usersArray=$query->getArrayResult();// array of partially loaded CmsUser and CmsArticle fields
$users=$query->getResult();// array of partially loaded CmsUser objects
"NEW" Operator Syntax
^^^^^^^^^^^^^^^^^^^^^
@@ -560,7 +590,101 @@ And then use the ``NEW`` DQL keyword :
$query=$em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, a.city, SUM(o.value)) FROM Customer c JOIN c.email e JOIN c.address a JOIN c.orders o GROUP BY c');
$users=$query->getResult();// array of CustomerDTO
Note that you can only pass scalar expressions to the constructor.
$query=$em->createQuery('SELECT NEW CustomerDTO(c.name, e.email, NEW AddressDTO(a.street, a.city, a.zip)) FROM Customer c JOIN c.email e JOIN c.address a');
$users=$query->getResult();// array of CustomerDTO
Note that you can only pass scalar expressions or other Data Transfer Objects to the constructor.
If you use your data transfer objects for multiple queries, and you would rather not have to
specify arguments that precede the ones you are really interested in, you can use named arguments.
Consider the following DTO, which uses optional arguments:
..code-block::php
<?php
classCustomerDTO
{
publicfunction__construct(
publicstring|null$name=null,
publicstring|null$email=null,
publicstring|null$city=null,
publicmixed|null$value=null,
publicAddressDTO|null$address=null,
){
}
}
You can specify arbitrary arguments in an arbitrary order by using the named argument syntax, and the ORM will try to match argument names with the selected column names.
The syntax relies on the NAMED keyword, like so:
..code-block::php
<?php
$query=$em->createQuery('SELECT NEW NAMED CustomerDTO(a.city, c.name) FROM Customer c JOIN c.address a');
$users=$query->getResult();// array of CustomerDTO
To define a custom name for a DTO constructor argument, you can either alias the column with the ``AS`` keyword.
The ``NAMED`` keyword must precede all DTO you want to instantiate :
..code-block::php
<?php
$query=$em->createQuery('SELECT NEW NAMED CustomerDTO(c.name, NEW NAMED AddressDTO(a.street, a.city, a.zip) AS address) FROM Customer c JOIN c.address a');
$users=$query->getResult();// array of CustomerDTO
If two arguments have the same name, a ``DuplicateFieldException`` is thrown.
If a field cannot be matched with a property name, a ``NoMatchingPropertyException`` is thrown. This typically happens when using functions without aliasing them.
You can hydrate an entity nested in a DTO :
..code-block::php
<?php
$query=$em->createQuery('SELECT NEW CustomerDTO(c.name, a AS address) FROM Customer c JOIN c.address a');
$users=$query->getResult();// array of CustomerDTO
@@ -30,7 +30,7 @@ table alias of the SQL table of the entity.
For the filter to correctly function, the following rules must be followed. Failure to do so will lead to unexpected results from the query cache.
1. Parameters for the query should be set on the filter object by ``SQLFilter#setParameter()`` before the filter is used by the ORM ( i.e. do not set parameters inside ``SQLFilter#addFilterConstraint()`` function ).
2. The filter must be deterministic. Don't change the values base on external inputs.
2. The filter must be deterministic. Don't change the values based on external inputs.
The ``SQLFilter#getParameter()`` function takes care of the proper quoting of parameters.
There is a limitation on the compatibility of Criteria comparisons.
You have to use scalar values only as the value in a comparison or
the behaviour between different backends is not the same.
Depending on whether the collection has already been loaded from the
database or not, criteria matching may happen at the database/SQL level
or on objects in memory. This may lead to different results and come
surprising, for example when a code change in one place leads to a collection
becoming initialized and, as a side effect, returning a different result
or even breaking a ``matching()`` call somewhere else. Also, collection
initialization state in practical use cases may differ from the one covered
in unit tests.
Database level comparisons are based on scalar representations of the values
stored in entity properties. The field names passed to expressions correspond
to property names. Comparison and sorting may be affected by
database-specific behavior. For example, MySQL enum types sort by index position,
not lexicographically by value.
In-memory handling is based on the ``Selectable`` API of `Doctrine Collections <https://www.doctrine-project.org/projects/doctrine-collections/en/stable/index.html#matching>`.
In this case, field names passed to expressions are being used to derive accessor
method names. Strict type comparisons are used for equal and not-equal checks,
and generally PHP language rules are being used for other comparison operators
or sorting.
As a general guidance, for consistent results use the Criteria API with scalar
values only. Note that ``DateTime`` and ``DateTimeImmutable`` are two predominant
examples of value objects that are *not* scalars.
Refrain from using special database-level column types or custom Doctrine Types
that may lead to database-specific comparison or sorting rules being applied, or
to database-level values being different from object field values.
Provide accessor methods for all entity fields used in criteria expressions,
and implement those methods in a way that their return value is the
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Query/AST/Functions/TrimFunction.php
-
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
- '~^Method Doctrine\\ORM\\Query\\ParameterTypeInferer\:\:inferType\(\) never returns ''[a-z_]+'' so it can be removed from the return type\.$~'
- '~^Method Doctrine\\ORM\\Query\\ParameterTypeInferer\:\:inferType\(\) never returns Doctrine\\DBAL\\(?:Array)?ParameterType\:\:[A-Z_]+ so it can be removed from the return type\.$~'
# DBAL 4 compatibility
-
message: '~^Method Doctrine\\ORM\\Query\\AST\\Functions\\TrimFunction::getTrimMode\(\) never returns .* so it can be removed from the return type\.$~'
path: src/Query/AST/Functions/TrimFunction.php
-
message: '~^Method Doctrine\\ORM\\Persisters\\Entity\\BasicEntityPersister\:\:getArrayBindingType\(\) never returns .* so it can be removed from the return type\.$~'
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.