Compare commits

...

44 Commits
2.9.4 ... 2.9.6

Author SHA1 Message Date
Alexander M. Turek
5f768742a0 Run PHP 8.1 CI with stable dependencies (#9058) 2021-10-02 19:37:08 +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
Csupity Laszlo
2362aa1a7a Fix locking non-existing entity (#9053) 2021-09-30 23:29:34 +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
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
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
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
Alexander M. Turek
45553556d5 Fix class casing and avoid name collisions 2021-09-11 13:41:46 +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
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
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
1963733311 Merge pull request #8959 from norkunas/fix-typehint
Fix `getEntityChangeSet` return typehint
2021-08-27 08:27:04 +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
Tomas
1de4020dc9 Fix getEntityChangeSet return typehint 2021-08-25 12:38:44 +03: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
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
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
Michael Olšavský
5685dc05f6 Fix mapped superclass missing in discriminator map 2021-08-09 16:24:37 +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
60 changed files with 1064 additions and 585 deletions

View File

@@ -19,6 +19,7 @@ jobs:
- "7.3"
- "7.4"
- "8.0"
- "8.1"
steps:
- name: "Checkout"

View File

@@ -1,7 +1,7 @@
| [3.0.x][3.0] | [2.9.x][2.9] | [2.8.x][2.8] |
| [3.0.x][3.0] | [2.10.x][2.10] | [2.9.x][2.9] |
|:----------------:|:----------------:|:----------:|
| [![Build status][3.0 image]][3.0] | [![Build status][2.9 image]][2.9] | [![Build status][2.8 image]][2.8] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.9 coverage image]][2.9 coverage] | [![Coverage Status][2.8 coverage image]][2.8 coverage] |
| [![Build status][3.0 image]][3.0] | [![Build status][2.10 image]][2.10] | [![Build status][2.9 image]][2.9] |
| [![Coverage Status][3.0 coverage image]][3.0 coverage]| [![Coverage Status][2.10 coverage image]][2.10 coverage] | [![Coverage Status][2.9 coverage image]][2.9 coverage] |
Doctrine 2 is an object-relational mapper (ORM) for PHP 7.1+ that provides transparent persistence
for PHP objects. It sits on top of a powerful database abstraction layer (DBAL). One of its key features
@@ -24,7 +24,7 @@ without requiring unnecessary code duplication.
[2.9]: https://github.com/doctrine/orm/tree/2.9.x
[2.9 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.9.x/graph/badge.svg
[2.9 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.9.x
[2.8 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg
[2.8]: https://github.com/doctrine/orm/tree/2.8
[2.8 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.8.x/graph/badge.svg
[2.8 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.8.x
[2.10 image]: https://github.com/doctrine/orm/actions/workflows/continuous-integration.yml/badge.svg?branch=2.10.x
[2.10]: https://github.com/doctrine/orm/tree/2.10.x
[2.10 coverage image]: https://codecov.io/gh/doctrine/orm/branch/2.10.x/graph/badge.svg
[2.10 coverage]: https://codecov.io/gh/doctrine/orm/branch/2.10.x

View File

@@ -107,24 +107,16 @@ The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctri
please refrain from checking the ORM version at runtime or use
[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/).
## 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

View File

@@ -37,12 +37,12 @@
"require-dev": {
"doctrine/coding-standard": "^9.0",
"phpbench/phpbench": "^0.16.10 || ^1.0",
"phpstan/phpstan": "0.12.94",
"phpstan/phpstan": "0.12.99",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
"squizlabs/php_codesniffer": "3.6.0",
"symfony/cache": "^4.4 || ^5.2",
"symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0",
"vimeo/psalm": "4.7.0"
"vimeo/psalm": "4.10.0"
},
"suggest": {
"symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0",

View File

@@ -134,6 +134,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)
{
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

View File

@@ -659,9 +659,8 @@ postFlush
preUpdate
~~~~~~~~~
PreUpdate is the most restrictive to use event, since it is called
right before an update statement is called for an entity inside the
``EntityManager#flush()`` method. Note that this event is not
PreUpdate is called inside the ``EntityManager#flush()`` method,
right before an SQL ``UPDATE`` statement. This event is not
triggered when the computed changeset is empty.
Changes to associations of the updated entity are never allowed in

View File

@@ -579,7 +579,7 @@ The Cache Mode controls how a particular query interacts with the second-level c
.. note::
The the default query cache mode is ```Cache::MODE_NORMAL```
The default query cache mode is ```Cache::MODE_NORMAL```
DELETE / UPDATE queries
~~~~~~~~~~~~~~~~~~~~~~~

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,

View File

@@ -308,6 +308,9 @@
</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="optional" />
<xs:attribute name="column-prefix" type="xs:string" use="optional" />

View File

@@ -886,7 +886,6 @@ abstract class AbstractQuery
*
* @throws NoResultException If the query returned no result.
* @throws NonUniqueResultException If the query result is not unique.
* @throws NoResultException If the query returned no result.
*/
public function getSingleScalarResult()
{

View File

@@ -473,7 +473,9 @@ use function sprintf;
case $lockMode === LockMode::OPTIMISTIC:
$entity = $persister->load($sortedId);
$unitOfWork->lock($entity, $lockMode, $lockVersion);
if ($entity !== null) {
$unitOfWork->lock($entity, $lockMode, $lockVersion);
}
return $entity;

View File

@@ -169,7 +169,7 @@ interface EntityManagerInterface extends ObjectManager
* @psalm-param class-string<T> $entityName
*
* @return object|null The entity reference.
* @psalm-return ?T
* @psalm-return T|null
*
* @throws ORMException
*
@@ -194,8 +194,12 @@ interface EntityManagerInterface extends ObjectManager
*
* @param string $entityName The name of the entity type.
* @param mixed $identifier The entity identifier.
* @psalm-param class-string<T> $entityName
*
* @return object|null The (partial) entity reference.
* @return object|null The (partial) entity reference
* @psalm-return T|null
*
* @template T
*/
public function getPartialReference($entityName, $identifier);

View File

@@ -21,6 +21,7 @@
namespace Doctrine\ORM\Event;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\PersistentCollection;
use InvalidArgumentException;
use function get_class;
@@ -31,12 +32,13 @@ use function sprintf;
*/
class PreUpdateEventArgs extends LifecycleEventArgs
{
/** @var array<string,array<int,mixed>> */
/** @var array<string, array{mixed, mixed}|PersistentCollection> */
private $entityChangeSet;
/**
* @param object $entity
* @param array<string,array<int,mixed>> $changeSet
* @param object $entity
* @param mixed[][] $changeSet
* @psalm-param array<string, array{mixed, mixed}|PersistentCollection> $changeSet
*/
public function __construct($entity, EntityManagerInterface $em, array &$changeSet)
{
@@ -48,7 +50,8 @@ class PreUpdateEventArgs extends LifecycleEventArgs
/**
* Retrieves entity changeset.
*
* @return array<string,array<int,mixed>>
* @return mixed[][]
* @psalm-return array<string, array{mixed, mixed}|PersistentCollection>
*/
public function getEntityChangeSet()
{

View File

@@ -32,7 +32,7 @@ class IdentityGenerator extends AbstractIdGenerator
/**
* The name of the sequence to pass to lastInsertId(), if any.
*
* @var string
* @var string|null
*/
private $sequenceName;

View File

@@ -103,27 +103,43 @@ class SequenceGenerator extends AbstractIdGenerator implements Serializable
/**
* @return string
*
* @final
*/
public function serialize()
{
return serialize(
[
'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName,
]
);
return serialize($this->__serialize());
}
/**
* @return array<string, mixed>
*/
public function __serialize(): array
{
return [
'allocationSize' => $this->_allocationSize,
'sequenceName' => $this->_sequenceName,
];
}
/**
* @param string $serialized
*
* @return void
*
* @final
*/
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->__unserialize(unserialize($serialized));
}
$this->_sequenceName = $array['sequenceName'];
$this->_allocationSize = $array['allocationSize'];
/**
* @param array<string, mixed> $data
*/
public function __unserialize(array $data): void
{
$this->_sequenceName = $data['sequenceName'];
$this->_allocationSize = $data['allocationSize'];
}
}

View File

@@ -39,7 +39,7 @@ final class Cache implements Annotation
*/
public $usage = 'READ_ONLY';
/** @var string Cache region name. */
/** @var string|null Cache region name. */
public $region;
public function __construct(string $usage = 'READ_ONLY', ?string $region = null)

View File

@@ -285,7 +285,10 @@ class ClassMetadataFactory extends AbstractClassMetadataFactory
}
} else {
assert($parent instanceof ClassMetadataInfo); // https://github.com/doctrine/orm/issues/8746
if ((! $class->reflClass || ! $class->reflClass->isAbstract()) && ! in_array($class->name, $parent->discriminatorMap)) {
if (
(! $class->reflClass || ! $class->reflClass->isAbstract())
&& ! in_array($class->name, $class->discriminatorMap)
) {
throw MappingException::mappedClassNotPartOfDiscriminatorMap($class->name, $class->rootEntityName);
}
}

View File

@@ -630,8 +630,8 @@ class ClassMetadataInfo implements ClassMetadata
* )
* </code>
*
* @var mixed[]
* @psalm-var array{sequenceName: string, allocationSize: int, initialValue: int}
* @var array<string, mixed>
* @psalm-var array{sequenceName: string, allocationSize: string, initialValue: string}
* @todo Merge with tableGeneratorDefinition into generic generatorDefinition
*/
public $sequenceGeneratorDefinition;
@@ -1152,7 +1152,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* @param string $fieldName
* @param array $cache
* @psalm-param array{usage?: int, region?: string} $cache
* @psalm-param array{usage?: int, region?: string|null} $cache
*
* @return int[]|string[]
* @psalm-return array{usage: int, region: string|null}
@@ -3279,7 +3279,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* Sets definition.
*
* @psalm-param array<string, string> $definition
* @psalm-param array<string, string|null> $definition
*
* @return void
*/

View File

@@ -31,7 +31,7 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class CustomIdGenerator implements Annotation
{
/** @var string */
/** @var string|null */
public $class;
public function __construct(?string $class = null)

View File

@@ -702,11 +702,11 @@ class AnnotationDriver extends AbstractAnnotationDriver
*
* @return mixed[]
* @psalm-return array{
* name: string,
* name: string|null,
* unique: bool,
* nullable: bool,
* onDelete: mixed,
* columnDefinition: string,
* columnDefinition: string|null,
* referencedColumnName: string
* }
*/

View File

@@ -522,11 +522,11 @@ class AttributeDriver extends AnnotationDriver
*
* @return mixed[]
* @psalm-return array{
* name: string,
* name: string|null,
* unique: bool,
* nullable: bool,
* onDelete: mixed,
* columnDefinition: string,
* columnDefinition: string|null,
* referencedColumnName: string
* }
*/

View File

@@ -31,7 +31,7 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_CLASS)]
final class Entity implements Annotation
{
/** @var string */
/** @var string|null */
public $repositoryClass;
/** @var bool */

View File

@@ -31,26 +31,26 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class Index implements Annotation
{
/** @var string */
/** @var string|null */
public $name;
/** @var array<string> */
/** @var array<string>|null */
public $columns;
/** @var array<string> */
/** @var array<string>|null */
public $fields;
/** @var array<string> */
/** @var array<string>|null */
public $flags;
/** @var array<string,mixed> */
/** @var array<string,mixed>|null */
public $options;
/**
* @param array<string> $columns
* @param array<string> $fields
* @param array<string> $flags
* @param array<string> $options
* @param array<string>|null $columns
* @param array<string>|null $fields
* @param array<string>|null $flags
* @param array<string>|null $options
*/
public function __construct(
?array $columns = null,

View File

@@ -27,7 +27,7 @@ use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class InverseJoinColumn implements Annotation
{
/** @var string */
/** @var string|null */
public $name;
/** @var string */
@@ -42,13 +42,13 @@ final class InverseJoinColumn implements Annotation
/** @var mixed */
public $onDelete;
/** @var string */
/** @var string|null */
public $columnDefinition;
/**
* Field name used in non-object hydration (array/scalar).
*
* @var string
* @var string|null
*/
public $fieldName;

View File

@@ -31,7 +31,7 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class JoinColumn implements Annotation
{
/** @var string */
/** @var string|null */
public $name;
/** @var string */
@@ -46,13 +46,13 @@ final class JoinColumn implements Annotation
/** @var mixed */
public $onDelete;
/** @var string */
/** @var string|null */
public $columnDefinition;
/**
* Field name used in non-object hydration (array/scalar).
*
* @var string
* @var string|null
*/
public $fieldName;

View File

@@ -31,10 +31,10 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class JoinTable implements Annotation
{
/** @var string */
/** @var string|null */
public $name;
/** @var string */
/** @var string|null */
public $schema;
/** @var array<\Doctrine\ORM\Mapping\JoinColumn> */

View File

@@ -35,13 +35,13 @@ final class ManyToMany implements Annotation
/** @var string|null */
public $targetEntity;
/** @var string */
/** @var string|null */
public $mappedBy;
/** @var string */
/** @var string|null */
public $inversedBy;
/** @var array<string> */
/** @var string[]|null */
public $cascade;
/**
@@ -55,11 +55,11 @@ final class ManyToMany implements Annotation
/** @var bool */
public $orphanRemoval = false;
/** @var string */
/** @var string|null */
public $indexBy;
/**
* @param array<string> $cascade
* @param string[]|null $cascade
*/
public function __construct(
?string $targetEntity = null,

View File

@@ -31,10 +31,10 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class ManyToOne implements Annotation
{
/** @var string */
/** @var string|null */
public $targetEntity;
/** @var array<string> */
/** @var string[]|null */
public $cascade;
/**
@@ -45,11 +45,11 @@ final class ManyToOne implements Annotation
*/
public $fetch = 'LAZY';
/** @var string */
/** @var string|null */
public $inversedBy;
/**
* @param array<string> $cascade
* @param string[]|null $cascade
*/
public function __construct(
?string $targetEntity = null,

View File

@@ -31,7 +31,7 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_CLASS)]
final class MappedSuperclass implements Annotation
{
/** @var string */
/** @var string|null */
public $repositoryClass;
public function __construct(?string $repositoryClass = null)

View File

@@ -55,7 +55,7 @@ final class OneToMany implements Annotation
public $indexBy;
/**
* @param array<string> $cascade
* @param string[]|null $cascade
*/
public function __construct(
?string $mappedBy = null,

View File

@@ -31,16 +31,16 @@ use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class OneToOne implements Annotation
{
/** @var string */
/** @var string|null */
public $targetEntity;
/** @var string */
/** @var string|null */
public $mappedBy;
/** @var string */
/** @var string|null */
public $inversedBy;
/** @var array<string> */
/** @var array<string>|null */
public $cascade;
/**
@@ -55,7 +55,7 @@ final class OneToOne implements Annotation
public $orphanRemoval = false;
/**
* @param array<string> $cascade
* @param array<string>|null $cascade
*/
public function __construct(
?string $mappedBy = null,

View File

@@ -238,6 +238,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$targetClass = $this->em->getClassMetadata($mapping['targetEntity']);
$onConditions = $this->getOnConditionSQL($mapping);
$whereClauses = $params = [];
$paramTypes = [];
if (! $mapping['isOwningSide']) {
$associationSourceClass = $targetClass;
@@ -253,6 +254,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$params[] = $ownerMetadata->containsForeignIdentifier
? $id[$ownerMetadata->getFieldForColumn($value)]
: $id[$ownerMetadata->fieldNames[$value]];
$paramTypes[] = PersisterHelper::getTypeOfColumn($value, $ownerMetadata, $this->em);
}
$parameters = $this->expandCriteriaParameters($criteria);
@@ -263,6 +265,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$field = $this->quoteStrategy->getColumnName($name, $targetClass, $this->platform);
$whereClauses[] = sprintf('te.%s %s ?', $field, $operator);
$params[] = $value;
$paramTypes[] = PersisterHelper::getTypeOfColumn($field, $targetClass, $this->em);
}
$tableName = $this->quoteStrategy->getTableName($targetClass, $this->platform);
@@ -281,7 +284,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$sql .= $this->getLimitSql($criteria);
$stmt = $this->conn->executeQuery($sql, $params);
$stmt = $this->conn->executeQuery($sql, $params, $paramTypes);
return $this
->em

View File

@@ -26,7 +26,7 @@ use Doctrine\ORM\Query\SqlWalker;
use function strtolower;
/**
* "DATE_ADD(date1, interval, unit)"
* "DATE_SUB(date1, interval, unit)"
*
* @link www.doctrine-project.org
*/

View File

@@ -33,7 +33,7 @@ class From
/** @var string */
protected $alias;
/** @var string */
/** @var string|null */
protected $indexBy;
/**
@@ -65,7 +65,7 @@ class From
}
/**
* @return string
* @return string|null
*/
public function getIndexBy()
{

View File

@@ -41,25 +41,25 @@ class Join
/** @var string */
protected $join;
/** @var string */
/** @var string|null */
protected $alias;
/** @var string */
/** @var string|null */
protected $conditionType;
/** @var string */
/** @var string|Comparison|Composite|null */
protected $condition;
/** @var string */
/** @var string|null */
protected $indexBy;
/**
* @param string $joinType The condition type constant. Either INNER_JOIN or LEFT_JOIN.
* @param string $join The relationship to join.
* @param string|null $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
* @param string $joinType The condition type constant. Either INNER_JOIN or LEFT_JOIN.
* @param string $join The relationship to join.
* @param string|null $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|Comparison|Composite|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
*/
public function __construct($joinType, $join, $alias = null, $conditionType = null, $condition = null, $indexBy = null)
{
@@ -88,7 +88,7 @@ class Join
}
/**
* @return string
* @return string|null
*/
public function getAlias()
{
@@ -96,7 +96,7 @@ class Join
}
/**
* @return string
* @return string|null
*/
public function getConditionType()
{
@@ -104,7 +104,7 @@ class Join
}
/**
* @return string
* @return string|Comparison|Composite|null
*/
public function getCondition()
{
@@ -112,7 +112,7 @@ class Join
}
/**
* @return string
* @return string|null
*/
public function getIndexBy()
{

View File

@@ -396,8 +396,6 @@ class QueryBuilder
*/
private function findRootAlias(string $alias, string $parentAlias): string
{
$rootAlias = null;
if (in_array($parentAlias, $this->getRootAliases())) {
$rootAlias = $parentAlias;
} elseif (isset($this->joinRootAliases[$parentAlias])) {
@@ -454,8 +452,8 @@ class QueryBuilder
* $qb->getRootAliases(); // array('u')
* </code>
*
* @return mixed[]
* @psalm-return list<mixed>
* @return string[]
* @psalm-return list<string>
*/
public function getRootAliases()
{
@@ -489,8 +487,8 @@ class QueryBuilder
* $qb->getAllAliases(); // array('u','a')
* </code>
*
* @return mixed[]
* @psalm-return list<mixed>
* @return string[]
* @psalm-return list<string>
*/
public function getAllAliases()
{
@@ -509,8 +507,8 @@ class QueryBuilder
* $qb->getRootEntities(); // array('User')
* </code>
*
* @return mixed[]
* @psalm-return list<mixed>
* @return string[]
* @psalm-return list<string>
*/
public function getRootEntities()
{
@@ -958,11 +956,11 @@ class QueryBuilder
* ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
* </code>
*
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
*
* @return self
*/
@@ -984,11 +982,11 @@ class QueryBuilder
* ->from('User', 'u')
* ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
*
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
*
* @return static
*/
@@ -1024,11 +1022,11 @@ class QueryBuilder
* ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
* </code>
*
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
* @param string $join The relationship to join.
* @param string $alias The alias of the join.
* @param string|null $conditionType The condition type constant. Either ON or WITH.
* @param string|Expr\Comparison|Expr\Composite|null $condition The condition for the join.
* @param string|null $indexBy The index for the join.
*
* @return static
*/

View File

@@ -255,7 +255,7 @@ class SchemaValidator
}
}
if (! $class->isInheritanceTypeNone() && ! $class->isRootEntity() && array_search($class->name, $class->discriminatorMap) === false) {
if (! $class->isInheritanceTypeNone() && ! $class->isRootEntity() && ! $class->isMappedSuperclass && array_search($class->name, $class->discriminatorMap) === false) {
$ce[] = "Entity class '" . $class->name . "' is part of inheritance hierarchy, but is " .
"not mapped in the root entity '" . $class->rootEntityName . "' discriminator map. " .
'All subclasses must be listed in the discriminator map.';

View File

@@ -590,7 +590,7 @@ class UnitOfWork implements PropertyChangedListener
* @param object $entity
*
* @return mixed[][]
* @psalm-return array<string, array{mixed, mixed}>
* @psalm-return array<string, array{mixed, mixed}|PersistentCollection>
*/
public function & getEntityChangeSet($entity)
{
@@ -2872,6 +2872,10 @@ class UnitOfWork implements PropertyChangedListener
break;
}
if ($newValue === null) {
break;
}
// PERF: Inlined & optimized code from UnitOfWork#registerManaged()
$newValueOid = spl_object_hash($newValue);
$this->entityIdentifiers[$newValueOid] = $associatedId;
@@ -2892,7 +2896,7 @@ class UnitOfWork implements PropertyChangedListener
$this->originalEntityData[$oid][$field] = $newValue;
$class->reflFields[$field]->setValue($entity, $newValue);
if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE) {
if ($assoc['inversedBy'] && $assoc['type'] & ClassMetadata::ONE_TO_ONE && $newValue !== null) {
$inverseAssoc = $targetClass->associationMappings[$assoc['inversedBy']];
$targetClass->reflFields[$inverseAssoc['fieldName']]->setValue($newValue, $entity);
}

View File

@@ -247,7 +247,6 @@
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php</exclude-pattern>
<exclude-pattern>lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php</exclude-pattern>
<!-- the impact of changing this would be too big -->
<exclude-pattern>tests/Doctrine/Tests/DbalFunctionalTestCase.php</exclude-pattern>
<exclude-pattern>tests/Doctrine/Tests/OrmFunctionalTestCase.php</exclude-pattern>
</rule>
<rule ref="Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps">

View File

@@ -160,6 +160,16 @@ parameters:
count: 3
path: lib/Doctrine/ORM/EntityManager.php
-
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getPartialReference\\(\\) should return T\\|null but returns object\\.$#"
count: 1
path: lib/Doctrine/ORM/EntityManager.php
-
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getPartialReference\\(\\) should return T\\|null but returns object\\|null\\.$#"
count: 1
path: lib/Doctrine/ORM/EntityManager.php
-
message: "#^Method Doctrine\\\\ORM\\\\EntityManager\\:\\:getReference\\(\\) should return T\\|null but returns Doctrine\\\\Common\\\\Proxy\\\\Proxy\\.$#"
count: 1
@@ -450,11 +460,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Parameter \\#1 \\$definition of method Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:setSequenceGeneratorDefinition\\(\\) expects array\\<string, string\\>, array\\<string, int\\|string\\> given\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Parameter \\#1 \\$definition of method Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<object\\>\\:\\:setSequenceGeneratorDefinition\\(\\) expects array\\<string, string\\>, array\\<string, int\\|string\\|true\\> given\\.$#"
count: 1
@@ -495,6 +500,11 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Parameter \\#2 \\$allocationSize of class Doctrine\\\\ORM\\\\Id\\\\SequenceGenerator constructor expects int, string given\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Parameter \\#2 \\$class of method Doctrine\\\\ORM\\\\Mapping\\\\QuoteStrategy\\:\\:getSequenceName\\(\\) expects Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadata, Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo given\\.$#"
count: 2
@@ -551,12 +561,12 @@ parameters:
path: lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php
-
message: "#^Array \\(array\\<string, array\\|string\\>\\) does not accept key 'options'\\.$#"
message: "#^Array \\(array\\('name' \\=\\> string, 'schema' \\=\\> string, 'indexes' \\=\\> array, 'uniqueConstraints' \\=\\> array\\)\\) does not accept key 'options'\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Array \\(array\\<string, array\\|string\\>\\) does not accept key 'quoted'\\.$#"
message: "#^Array \\(array\\('name' \\=\\> string, 'schema' \\=\\> string, 'indexes' \\=\\> array, 'uniqueConstraints' \\=\\> array\\)\\) does not accept key 'quoted'\\.$#"
count: 2
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -590,11 +600,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Property Doctrine\\\\ORM\\\\Mapping\\\\ClassMetadataInfo\\<T of object\\>\\:\\:\\$sequenceGeneratorDefinition \\(array\\('sequenceName' \\=\\> string, 'allocationSize' \\=\\> int, 'initialValue' \\=\\> int\\)\\) does not accept array\\<string, string\\|true\\>\\.$#"
count: 1
path: lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
-
message: "#^Result of && is always false\\.$#"
count: 2
@@ -1421,7 +1426,7 @@ parameters:
path: lib/Doctrine/ORM/Query/FilterCollection.php
-
message: "#^Array \\(array\\<int, Doctrine\\\\ORM\\\\Query\\\\AST\\\\SelectExpression\\>\\) does not accept key string\\.$#"
message: "#^Array \\(array\\<int, Doctrine\\\\ORM\\\\Query\\\\AST\\\\SelectExpression\\>\\) does not accept key non\\-empty\\-string\\.$#"
count: 1
path: lib/Doctrine/ORM/Query/Parser.php
@@ -1471,11 +1476,6 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
-
message: "#^Parameter \\#2 \\$mode of method Doctrine\\\\ORM\\\\Query\\\\ResultSetMappingBuilder\\:\\:getColumnAliasMap\\(\\) expects 1\\|2\\|3, int given\\.$#"
count: 2
path: lib/Doctrine/ORM/Query/ResultSetMappingBuilder.php
-
message: "#^Array \\(array\\<string, array\\<int, string\\>\\|string\\>\\) does not accept key int\\.$#"
count: 1
@@ -2158,7 +2158,7 @@ parameters:
-
message: "#^Parameter \\#2 \\$value of method SimpleXMLElement\\:\\:addAttribute\\(\\) expects string, int given\\.$#"
count: 6
count: 4
path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php
-
@@ -2216,6 +2216,16 @@ parameters:
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Parameter \\#2 \\$allocationSize of method Doctrine\\\\DBAL\\\\Schema\\\\Schema\\:\\:createSequence\\(\\) expects int, string given\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Parameter \\#3 \\$initialValue of method Doctrine\\\\DBAL\\\\Schema\\\\Schema\\:\\:createSequence\\(\\) expects int, string given\\.$#"
count: 1
path: lib/Doctrine/ORM/Tools/SchemaTool.php
-
message: "#^Parameter \\#2 \\$code of class Doctrine\\\\ORM\\\\Tools\\\\ToolsException constructor expects int, string given\\.$#"
count: 1

View File

@@ -14,8 +14,5 @@ parameters:
phpVersion: 70100
ignoreErrors:
# The class was added in PHP 8.1
- '/^Attribute class ReturnTypeWillChange does not exist.$/'
# https://github.com/doctrine/collections/pull/282
- '/Variable \$offset in isset\(\) always exists and is not nullable\./'

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.7.0@d4377c0baf3ffbf0b1ec6998e8d1be2a40971005">
<files psalm-version="4.10.0@916b098b008f6de4543892b1e0651c1c3b92cbfa">
<file src="lib/Doctrine/ORM/AbstractQuery.php">
<DeprecatedClass occurrences="1">
<code>IterableResult</code>
@@ -103,14 +103,20 @@
<NullableReturnStatement occurrences="1">
<code>$this-&gt;fileLockRegionDirectory</code>
</NullableReturnStatement>
<ParamNameMismatch occurrences="1">
<code>$em</code>
</ParamNameMismatch>
<RedundantCastGivenDocblockType occurrences="1">
<code>(string) $fileLockRegionDirectory</code>
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Cache/DefaultCollectionHydrator.php">
<InvalidNullableReturnType occurrences="1">
<InvalidReturnStatement occurrences="1">
<code>$list</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="1">
<code>loadCacheEntry</code>
</InvalidNullableReturnType>
</InvalidReturnType>
<MissingClosureParamType occurrences="2">
<code>$entity</code>
<code>$index</code>
@@ -481,18 +487,21 @@
<code>is_object($entity)</code>
<code>is_object($entity)</code>
</DocblockTypeContradiction>
<InvalidReturnStatement occurrences="7">
<InvalidReturnStatement occurrences="9">
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity instanceof $class-&gt;name ? $entity : null</code>
<code>$entity instanceof $class-&gt;name ? $entity : null</code>
<code>$persister-&gt;load($sortedId, null, null, [], $lockMode)</code>
<code>$persister-&gt;loadById($sortedId)</code>
<code>$this-&gt;metadataFactory-&gt;getMetadataFor($className)</code>
</InvalidReturnStatement>
<InvalidReturnType occurrences="3">
<InvalidReturnType occurrences="4">
<code>?T</code>
<code>getClassMetadata</code>
<code>getPartialReference</code>
<code>getReference</code>
</InvalidReturnType>
<InvalidScalarArgument occurrences="2">
@@ -507,6 +516,16 @@
<code>EntityRepository&lt;T&gt;</code>
<code>newHydrator</code>
</MoreSpecificReturnType>
<ParamNameMismatch occurrences="8">
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entity</code>
<code>$entityName</code>
<code>$entityName</code>
</ParamNameMismatch>
<PossiblyNullArgument occurrences="3">
<code>$config-&gt;getProxyDir()</code>
<code>$config-&gt;getProxyNamespace()</code>
@@ -562,10 +581,6 @@
<code>?T</code>
<code>Collection&lt;int, T&gt;</code>
</InvalidReturnType>
<MoreSpecificImplementedParamType occurrences="2">
<code>$criteria</code>
<code>$criteria</code>
</MoreSpecificImplementedParamType>
<PropertyTypeCoercion occurrences="1">
<code>$em</code>
</PropertyTypeCoercion>
@@ -616,11 +631,6 @@
<code>(string) $em-&gt;getConnection()-&gt;lastInsertId($this-&gt;sequenceName)</code>
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Id/IdentityGenerator.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$sequenceName</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Id/SequenceGenerator.php">
<DeprecatedMethod occurrences="2">
<code>fetchColumn</code>
@@ -874,11 +884,6 @@
<code>(string) $customIdGenerator</code>
</RedundantCastGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Mapping/Cache.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$region</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/ClassMetadata.php">
<PropertyNotSetInConstructor occurrences="8">
<code>ClassMetadata</code>
@@ -935,7 +940,7 @@
</InvalidArrayOffset>
<InvalidScalarArgument occurrences="2">
<code>$definition</code>
<code>$parent-&gt;sequenceGeneratorDefinition</code>
<code>$definition['allocationSize']</code>
</InvalidScalarArgument>
<MissingConstructor occurrences="2">
<code>$driver</code>
@@ -1024,16 +1029,15 @@
<code>$class</code>
<code>$subclass</code>
</ArgumentTypeCoercion>
<DeprecatedProperty occurrences="2">
<DeprecatedProperty occurrences="4">
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
<code>$this-&gt;columnNames</code>
</DeprecatedProperty>
<DocblockTypeContradiction occurrences="1">
<code>$this-&gt;table</code>
</DocblockTypeContradiction>
<ImplementedReturnTypeMismatch occurrences="1">
<code>string|null</code>
</ImplementedReturnTypeMismatch>
<InvalidDocblock occurrences="4">
<code>protected function _validateAndCompleteAssociationMapping(array $mapping)</code>
<code>protected function _validateAndCompleteManyToManyMapping(array $mapping)</code>
@@ -1075,6 +1079,11 @@
<code>$this-&gt;reflFields[$name]</code>
<code>$this-&gt;reflFields[$this-&gt;identifier[0]]</code>
</NullableReturnStatement>
<ParamNameMismatch occurrences="3">
<code>$entity</code>
<code>$fieldName</code>
<code>$fieldName</code>
</ParamNameMismatch>
<PossiblyNullArgument occurrences="11">
<code>$class</code>
<code>$class</code>
@@ -1161,11 +1170,6 @@
<code>$name</code>
</MissingConstructor>
</file>
<file src="lib/Doctrine/ORM/Mapping/CustomIdGenerator.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$class</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/DefaultEntityListenerResolver.php">
<DocblockTypeContradiction occurrences="1">
<code>is_object($object)</code>
@@ -1293,11 +1297,6 @@
<code>$this-&gt;reader-&gt;getPropertyAnnotation($property, Mapping\InverseJoinColumn::class)</code>
<code>$this-&gt;reader-&gt;getPropertyAnnotation($property, Mapping\JoinColumn::class)</code>
</PossiblyNullIterator>
<RawObjectIteration occurrences="3">
<code>$joinColumnAttributes</code>
<code>$this-&gt;reader-&gt;getPropertyAnnotation($property, Mapping\InverseJoinColumn::class)</code>
<code>$this-&gt;reader-&gt;getPropertyAnnotation($property, Mapping\JoinColumn::class)</code>
</RawObjectIteration>
<RedundantCondition occurrences="3">
<code>assert($method instanceof ReflectionMethod)</code>
<code>assert($method instanceof ReflectionMethod)</code>
@@ -1385,6 +1384,11 @@
<ArgumentTypeCoercion occurrences="1">
<code>$metadata</code>
</ArgumentTypeCoercion>
<DocblockTypeContradiction occurrences="3">
<code>$xmlRoot-&gt;getName() === 'embeddable'</code>
<code>$xmlRoot-&gt;getName() === 'entity'</code>
<code>$xmlRoot-&gt;getName() === 'mapped-superclass'</code>
</DocblockTypeContradiction>
<ImplicitToStringCast occurrences="1">
<code>$cacheMapping['usage']</code>
</ImplicitToStringCast>
@@ -1566,11 +1570,6 @@
<code>$columnPrefix</code>
</MissingParamType>
</file>
<file src="lib/Doctrine/ORM/Mapping/Entity.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$repositoryClass</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/EntityListenerResolver.php">
<MissingReturnType occurrences="1">
<code>register</code>
@@ -1588,33 +1587,15 @@
<code>$name</code>
</MissingConstructor>
</file>
<file src="lib/Doctrine/ORM/Mapping/Index.php">
<PossiblyNullPropertyAssignmentValue occurrences="4">
<code>$columns</code>
<code>$fields</code>
<code>$flags</code>
<code>$name</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/InverseJoinColumn.php">
<MissingParamType occurrences="1">
<code>$onDelete</code>
</MissingParamType>
<PossiblyNullPropertyAssignmentValue occurrences="3">
<code>$columnDefinition</code>
<code>$fieldName</code>
<code>$name</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/JoinColumn.php">
<MissingParamType occurrences="1">
<code>$onDelete</code>
</MissingParamType>
<PossiblyNullPropertyAssignmentValue occurrences="3">
<code>$columnDefinition</code>
<code>$fieldName</code>
<code>$name</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/JoinColumns.php">
<MissingConstructor occurrences="1">
@@ -1626,30 +1607,6 @@
<code>$inverseJoinColumns</code>
<code>$joinColumns</code>
</MissingParamType>
<PossiblyNullPropertyAssignmentValue occurrences="2">
<code>$name</code>
<code>$schema</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/ManyToMany.php">
<PossiblyNullPropertyAssignmentValue occurrences="4">
<code>$cascade</code>
<code>$indexBy</code>
<code>$inversedBy</code>
<code>$mappedBy</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/ManyToOne.php">
<PossiblyNullPropertyAssignmentValue occurrences="3">
<code>$cascade</code>
<code>$inversedBy</code>
<code>$targetEntity</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/MappedSuperclass.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$repositoryClass</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/MappingException.php">
<MissingParamType occurrences="4">
@@ -1686,14 +1643,6 @@
<code>$targetEntity</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/OneToOne.php">
<PossiblyNullPropertyAssignmentValue occurrences="4">
<code>$cascade</code>
<code>$inversedBy</code>
<code>$mappedBy</code>
<code>$targetEntity</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Mapping/ReflectionEmbeddedProperty.php">
<ArgumentTypeCoercion occurrences="1">
<code>$this-&gt;embeddedClass</code>
@@ -1786,6 +1735,9 @@
<code>$key</code>
<code>$offset</code>
</MissingParamType>
<ParamNameMismatch occurrences="1">
<code>$value</code>
</ParamNameMismatch>
<PossiblyNullArgument occurrences="4">
<code>$this-&gt;association</code>
<code>$this-&gt;association</code>
@@ -1826,7 +1778,8 @@
</UndefinedInterfaceMethod>
</file>
<file src="lib/Doctrine/ORM/Persisters/Collection/ManyToManyPersister.php">
<DeprecatedMethod occurrences="5">
<DeprecatedMethod occurrences="6">
<code>executeUpdate</code>
<code>executeUpdate</code>
<code>executeUpdate</code>
<code>fetchColumn</code>
@@ -1836,7 +1789,7 @@
<FalsableReturnStatement occurrences="1">
<code>$this-&gt;conn-&gt;fetchColumn($sql, $params, 0, $types)</code>
</FalsableReturnStatement>
<PossiblyNullArgument occurrences="39">
<PossiblyNullArgument occurrences="45">
<code>$association</code>
<code>$collection-&gt;getOwner()</code>
<code>$collection-&gt;getOwner()</code>
@@ -1848,6 +1801,10 @@
<code>$collection-&gt;getOwner()</code>
<code>$collection-&gt;getOwner()</code>
<code>$filterMapping</code>
<code>$filterMapping</code>
<code>$indexBy</code>
<code>$mapping</code>
<code>$mapping</code>
<code>$mapping</code>
<code>$mapping</code>
<code>$mapping</code>
@@ -1856,6 +1813,8 @@
<code>$mapping</code>
<code>$mapping['joinTableColumns']</code>
<code>$mapping['relationToSourceKeyColumns']</code>
<code>$mapping['relationToSourceKeyColumns'][$joinTableColumn]</code>
<code>$mapping['relationToTargetKeyColumns'][$joinTableColumn]</code>
<code>$mapping['sourceEntity']</code>
<code>$mapping['sourceEntity']</code>
<code>$mapping['sourceEntity']</code>
@@ -1877,7 +1836,7 @@
<code>$owner</code>
<code>$owner</code>
</PossiblyNullArgument>
<PossiblyNullArrayAccess occurrences="32">
<PossiblyNullArrayAccess occurrences="36">
<code>$mapping['indexBy']</code>
<code>$mapping['isOwningSide']</code>
<code>$mapping['isOwningSide']</code>
@@ -1888,12 +1847,16 @@
<code>$mapping['joinTable']</code>
<code>$mapping['joinTable']</code>
<code>$mapping['joinTable']</code>
<code>$mapping['joinTable']['inverseJoinColumns']</code>
<code>$mapping['joinTable']['inverseJoinColumns']</code>
<code>$mapping['joinTableColumns']</code>
<code>$mapping['mappedBy']</code>
<code>$mapping['mappedBy']</code>
<code>$mapping['mappedBy']</code>
<code>$mapping['relationToSourceKeyColumns']</code>
<code>$mapping['relationToSourceKeyColumns']</code>
<code>$mapping['relationToSourceKeyColumns']</code>
<code>$mapping['relationToTargetKeyColumns']</code>
<code>$mapping['sourceEntity']</code>
<code>$mapping['sourceEntity']</code>
<code>$mapping['sourceEntity']</code>
@@ -1916,14 +1879,20 @@
<code>$sourceClass-&gt;associationMappings</code>
<code>$targetClass-&gt;associationMappings</code>
</PossiblyNullArrayOffset>
<PossiblyNullIterator occurrences="6">
<PossiblyNullIterator occurrences="8">
<code>$joinColumns</code>
<code>$mapping['joinTable']['inverseJoinColumns']</code>
<code>$mapping['joinTable']['inverseJoinColumns']</code>
<code>$mapping['joinTable']['joinColumns']</code>
<code>$mapping['joinTable']['joinColumns']</code>
<code>$mapping['joinTable']['joinColumns']</code>
<code>$mapping['joinTableColumns']</code>
<code>$mapping['relationToSourceKeyColumns']</code>
</PossiblyNullIterator>
<PossiblyNullReference occurrences="2">
<code>getFieldForColumn</code>
<code>getFieldForColumn</code>
</PossiblyNullReference>
</file>
<file src="lib/Doctrine/ORM/Persisters/Collection/OneToManyPersister.php">
<DeprecatedMethod occurrences="5">
@@ -2158,10 +2127,18 @@
<LessSpecificImplementedReturnType occurrences="1">
<code>mixed</code>
</LessSpecificImplementedReturnType>
<LessSpecificReturnStatement occurrences="2">
<code>parent::setHint($name, $value)</code>
<code>parent::setHydrationMode($hydrationMode)</code>
</LessSpecificReturnStatement>
<MoreSpecificImplementedParamType occurrences="2">
<code>$hydrationMode</code>
<code>$parameters</code>
</MoreSpecificImplementedParamType>
<MoreSpecificReturnType occurrences="2">
<code>self</code>
<code>self</code>
</MoreSpecificReturnType>
<PossiblyNullArgument occurrences="1">
<code>$this-&gt;getDQL()</code>
</PossiblyNullArgument>
@@ -2188,31 +2165,93 @@
<code>assert($rsm !== null)</code>
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ArithmeticFactor.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ArithmeticTerm.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/BetweenExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/CoalesceExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/CollectionMemberExpression.php">
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ComparisonExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ConditionalExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ConditionalFactor.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ConditionalPrimary.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ConditionalTerm.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/DeleteClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$aliasIdentificationVariable</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/DeleteStatement.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/EmptyCollectionComparisonExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/ExistsExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/FromClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php">
<PropertyNotSetInConstructor occurrences="1">
<code>$simpleArithmeticExpression</code>
@@ -2304,6 +2343,11 @@
<code>$this-&gt;unit-&gt;value</code>
</UndefinedPropertyFetch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Functions/FunctionNode.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Functions/IdentityFunction.php">
<PossiblyNullArrayAccess occurrences="1">
<code>$parser-&gt;getLexer()-&gt;token['value']</code>
@@ -2426,7 +2470,30 @@
<code>$stringPrimary</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/GeneralCaseExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/GroupByClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/HavingClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/IdentificationVariableDeclaration.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/InExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
@@ -2441,17 +2508,38 @@
<NullableReturnStatement occurrences="1">
<code>$sqlWalker-&gt;walkIndexBy($this)</code>
</NullableReturnStatement>
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PossiblyNullPropertyAssignmentValue occurrences="2">
<code>null</code>
<code>null</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Query/AST/InstanceOfExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="2">
<code>$not</code>
<code>$value</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Join.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/JoinAssociationDeclaration.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/JoinAssociationPathExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/JoinClassPathExpression.php">
<UndefinedMethod occurrences="1">
<code>walkJoinPathExpression</code>
@@ -2463,10 +2551,18 @@
</UndefinedMethod>
</file>
<file src="lib/Doctrine/ORM/Query/AST/LikeExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/NewObjectExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Node.php">
<DocblockTypeContradiction occurrences="1">
<code>is_array($obj)</code>
@@ -2476,11 +2572,27 @@
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$not</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/NullIfExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/OrderByClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/OrderByItem.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$type</code>
</PropertyNotSetInConstructor>
@@ -2491,31 +2603,94 @@
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/QuantifiedExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$type</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SelectClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SelectExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SelectStatement.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SimpleArithmeticExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SimpleCaseExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>null</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SimpleSelectClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$fieldIdentificationVariable</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SimpleWhenClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<UndefinedMethod occurrences="1">
<code>walkWhenClauseExpression</code>
</UndefinedMethod>
</file>
<file src="lib/Doctrine/ORM/Query/AST/Subselect.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/SubselectFromClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/UpdateClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PropertyNotSetInConstructor occurrences="1">
<code>$aliasIdentificationVariable</code>
</PropertyNotSetInConstructor>
</file>
<file src="lib/Doctrine/ORM/Query/AST/UpdateItem.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/UpdateStatement.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/AST/WhenClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>null</code>
</PossiblyNullPropertyAssignmentValue>
@@ -2523,6 +2698,11 @@
<code>walkWhenClauseExpression</code>
</UndefinedMethod>
</file>
<file src="lib/Doctrine/ORM/Query/AST/WhereClause.php">
<ParamNameMismatch occurrences="1">
<code>$sqlWalker</code>
</ParamNameMismatch>
</file>
<file src="lib/Doctrine/ORM/Query/Exec/AbstractSqlExecutor.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>null</code>
@@ -2594,6 +2774,9 @@
</NonInvariantDocblockPropertyType>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/Base.php">
<ArgumentTypeCoercion occurrences="1">
<code>$this-&gt;parts</code>
</ArgumentTypeCoercion>
<PossiblyInvalidCast occurrences="1">
<code>$this-&gt;parts[0]</code>
</PossiblyInvalidCast>
@@ -2604,23 +2787,15 @@
<code>$this-&gt;parts[0]</code>
</PossiblyInvalidCast>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/From.php">
<PossiblyNullPropertyAssignmentValue occurrences="1">
<code>$indexBy</code>
</PossiblyNullPropertyAssignmentValue>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/GroupBy.php">
<NonInvariantDocblockPropertyType occurrences="1">
<code>$parts</code>
</NonInvariantDocblockPropertyType>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/Join.php">
<PossiblyNullPropertyAssignmentValue occurrences="4">
<code>$alias</code>
<code>$condition</code>
<code>$conditionType</code>
<code>$indexBy</code>
</PossiblyNullPropertyAssignmentValue>
<PossiblyNullArgument occurrences="1">
<code>$this-&gt;conditionType</code>
</PossiblyNullArgument>
</file>
<file src="lib/Doctrine/ORM/Query/Expr/Literal.php">
<NonInvariantDocblockPropertyType occurrences="1">
@@ -2774,7 +2949,6 @@
<code>$this-&gt;lexer-&gt;token['value']</code>
<code>$this-&gt;lexer-&gt;token['value']</code>
<code>$this-&gt;query-&gt;getDQL()</code>
<code>$this-&gt;query-&gt;getDQL()</code>
<code>$token['value']</code>
<code>$token['value']</code>
<code>$token['value']</code>
@@ -3208,6 +3382,9 @@
<code>$updateItem</code>
<code>$whereClause</code>
</MissingParamType>
<ParamNameMismatch occurrences="1">
<code>$condPrimary</code>
</ParamNameMismatch>
<PossiblyNullReference occurrences="46">
<code>walkAggregateExpression</code>
<code>walkArithmeticExpression</code>
@@ -3401,7 +3578,9 @@
<code>new ClassMetadataExporter()</code>
<code>new EntityGenerator()</code>
</DeprecatedClass>
<InvalidNullableReturnType occurrences="1"/>
<InvalidNullableReturnType occurrences="1">
<code>int</code>
</InvalidNullableReturnType>
<MissingReturnType occurrences="1">
<code>configure</code>
</MissingReturnType>
@@ -3482,7 +3661,9 @@
</MissingReturnType>
</file>
<file src="lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php">
<InvalidNullableReturnType occurrences="1"/>
<InvalidNullableReturnType occurrences="1">
<code>int</code>
</InvalidNullableReturnType>
<NullableReturnStatement occurrences="1">
<code>$this-&gt;executeSchemaCommand($input, $output, new SchemaTool($em), $metadatas, $ui)</code>
</NullableReturnStatement>
@@ -3682,13 +3863,11 @@
<DeprecatedClass occurrences="1">
<code>AbstractExporter</code>
</DeprecatedClass>
<InvalidScalarArgument occurrences="6">
<InvalidScalarArgument occurrences="4">
<code>$field['length']</code>
<code>$field['length']</code>
<code>$field['precision']</code>
<code>$field['scale']</code>
<code>$sequenceDefinition['allocationSize']</code>
<code>$sequenceDefinition['initialValue']</code>
</InvalidScalarArgument>
<MissingClosureParamType occurrences="2">
<code>$m1</code>
@@ -3714,7 +3893,8 @@
</RedundantConditionGivenDocblockType>
</file>
<file src="lib/Doctrine/ORM/Tools/Export/Driver/YamlExporter.php">
<ArgumentTypeCoercion occurrences="2">
<ArgumentTypeCoercion occurrences="3">
<code>$array</code>
<code>$metadata-&gt;changeTrackingPolicy</code>
<code>$metadata-&gt;generatorType</code>
</ArgumentTypeCoercion>
@@ -3764,7 +3944,8 @@
<PossiblyNullIterator occurrences="1">
<code>$orderByClause-&gt;orderByItems</code>
</PossiblyNullIterator>
<PossiblyNullPropertyAssignmentValue occurrences="2">
<PossiblyNullPropertyAssignmentValue occurrences="3">
<code>$AST-&gt;orderByClause</code>
<code>$query-&gt;getFirstResult()</code>
<code>$query-&gt;getMaxResults()</code>
</PossiblyNullPropertyAssignmentValue>
@@ -3823,6 +4004,10 @@
<DocblockTypeContradiction occurrences="1">
<code>$definingClass</code>
</DocblockTypeContradiction>
<InvalidScalarArgument occurrences="2">
<code>$seqDef['allocationSize']</code>
<code>$seqDef['initialValue']</code>
</InvalidScalarArgument>
<MissingClosureParamType occurrences="1">
<code>$asset</code>
</MissingClosureParamType>

View File

@@ -1,39 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests;
use Doctrine\DBAL\Connection;
class DbalFunctionalTestCase extends DbalTestCase
{
/**
* Shared connection when a TestCase is run alone (outside of its functional suite).
*
* @var Connection|null
*/
private static $_sharedConn;
/** @var Connection */
protected $_conn;
protected function resetSharedConn(): void
{
$this->sharedFixture['conn'] = null;
self::$_sharedConn = null;
}
protected function setUp(): void
{
if (isset($this->sharedFixture['conn'])) {
$this->_conn = $this->sharedFixture['conn'];
} else {
if (! isset(self::$_sharedConn)) {
self::$_sharedConn = TestUtil::getConnection();
}
$this->_conn = self::$_sharedConn;
}
}
}

View File

@@ -1,12 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests;
/**
* Base testcase class for all dbal testcases.
*/
class DbalTestCase extends DoctrineTestCase
{
}

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Doctrine\Tests\ORM\Cache;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\ORM\Cache\Region;
use Doctrine\Tests\Mocks\CacheEntryMock;
@@ -19,7 +20,7 @@ abstract class AbstractRegionTest extends OrmFunctionalTestCase
/** @var Region */
protected $region;
/** @var ArrayCache */
/** @var Cache */
protected $cache;
protected function setUp(): void

View File

@@ -6,17 +6,17 @@ namespace Doctrine\Tests\ORM\Cache;
use BadMethodCallException;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\ORM\Cache\CollectionCacheEntry;
use Doctrine\ORM\Cache\Region;
use Doctrine\ORM\Cache\Region\DefaultRegion;
use Doctrine\Tests\Mocks\CacheEntryMock;
use Doctrine\Tests\Mocks\CacheKeyMock;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function assert;
use function class_exists;
/**
* @group DDC-2183
@@ -36,15 +36,11 @@ class DefaultRegionTest extends AbstractRegionTest
public function testSharedRegion(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Test only applies with doctrine/cache 1.x');
}
$cache = new SharedArrayCache();
$key = new CacheKeyMock('key');
$entry = new CacheEntryMock(['value' => 'foo']);
$region1 = new DefaultRegion('region1', $cache->createChild());
$region2 = new DefaultRegion('region2', $cache->createChild());
$region1 = new DefaultRegion('region1', DoctrineProvider::wrap($cache->createChild()));
$region2 = new DefaultRegion('region2', DoctrineProvider::wrap($cache->createChild()));
$this->assertFalse($region1->contains($key));
$this->assertFalse($region2->contains($key));
@@ -135,76 +131,71 @@ class DefaultRegionTest extends AbstractRegionTest
}
}
if (class_exists(ArrayCache::class)) {
/**
* Cache provider that offers child cache items (sharing the same array)
*
* Declared as a different class for readability purposes and kept in this file
* to keep its monstrosity contained.
*
* @internal
*/
final class SharedArrayCache extends ArrayCache
/**
* Cache provider that offers child cache items (sharing the same array)
*
* Declared as a different class for readability purposes and kept in this file
* to keep its monstrosity contained.
*
* @internal
*/
final class SharedArrayCache extends ArrayAdapter
{
public function createChild(): CacheItemPoolInterface
{
public function createChild(): Cache
{
return new class ($this) extends CacheProvider {
/** @var ArrayCache */
private $parent;
return new class ($this) implements CacheItemPoolInterface {
/** @var CacheItemPoolInterface */
private $parent;
public function __construct(ArrayCache $parent)
{
$this->parent = $parent;
}
public function __construct(CacheItemPoolInterface $parent)
{
$this->parent = $parent;
}
/**
* {@inheritDoc}
*/
protected function doFetch($id)
{
return $this->parent->doFetch($id);
}
public function getItem($key): CacheItemInterface
{
return $this->parent->getItem($key);
}
/**
* {@inheritDoc}
*/
protected function doContains($id)
{
return $this->parent->doContains($id);
}
public function getItems(array $keys = []): iterable
{
return $this->parent->getItems($keys);
}
/**
* {@inheritDoc}
*/
protected function doSave($id, $data, $lifeTime = 0)
{
return $this->parent->doSave($id, $data, $lifeTime);
}
public function hasItem($key): bool
{
return $this->parent->hasItem($key);
}
/**
* {@inheritDoc}
*/
protected function doDelete($id)
{
return $this->parent->doDelete($id);
}
public function clear(): bool
{
return $this->parent->clear();
}
/**
* {@inheritDoc}
*/
protected function doFlush()
{
return $this->parent->doFlush();
}
public function deleteItem($key): bool
{
return $this->parent->deleteItem($key);
}
/**
* {@inheritDoc}
*/
protected function doGetStats()
{
return $this->parent->doGetStats();
}
};
}
public function deleteItems(array $keys): bool
{
return $this->parent->deleteItems($keys);
}
public function save(CacheItemInterface $item): bool
{
return $this->parent->save($item);
}
public function saveDeferred(CacheItemInterface $item): bool
{
return $this->parent->saveDeferred($item);
}
public function commit(): bool
{
return $this->parent->commit();
}
};
}
}

View File

@@ -11,6 +11,8 @@ use Doctrine\Tests\Models\Quote\User as QuoteUser;
use Doctrine\Tests\Models\Tweet\Tweet;
use Doctrine\Tests\Models\Tweet\User;
use Doctrine\Tests\Models\Tweet\User as TweetUser;
use Doctrine\Tests\Models\ValueConversionType\InversedManyToManyExtraLazyEntity;
use Doctrine\Tests\Models\ValueConversionType\OwningManyToManyExtraLazyEntity;
use Doctrine\Tests\OrmFunctionalTestCase;
class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
@@ -19,6 +21,7 @@ class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
{
$this->useModelSet('tweet');
$this->useModelSet('quote');
$this->useModelSet('vct_manytomany_extralazy');
parent::setUp();
}
@@ -95,4 +98,31 @@ class PersistentCollectionCriteriaTest extends OrmFunctionalTestCase
$this->assertCount(1, $tweets);
$this->assertFalse($tweets->isInitialized());
}
public function testCanHandleComplexTypesOnAssociation(): void
{
$parent = new OwningManyToManyExtraLazyEntity();
$parent->id2 = 'Alice';
$this->_em->persist($parent);
$child = new InversedManyToManyExtraLazyEntity();
$child->id1 = 'Bob';
$this->_em->persist($child);
$parent->associatedEntities->add($child);
$this->_em->flush();
$this->_em->clear();
$parent = $this->_em->find(OwningManyToManyExtraLazyEntity::class, $parent->id2);
$criteria = Criteria::create()->where(Criteria::expr()->eq('id1', 'Bob'));
$result = $parent->associatedEntities->matching($criteria);
$this->assertCount(1, $result);
$this->assertEquals('Bob', $result[0]->id1);
}
}

View File

@@ -4,113 +4,98 @@ declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
use Doctrine\ORM\Query\ParserResult;
use Doctrine\Tests\OrmFunctionalTestCase;
use ReflectionProperty;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function class_exists;
use function assert;
use function count;
/**
* QueryCacheTest
*/
class QueryCacheTest extends OrmFunctionalTestCase
{
/** @var ReflectionProperty */
private $cacheDataReflection;
protected function setUp(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Test only applies with doctrine/cache 1.x');
}
$this->cacheDataReflection = new ReflectionProperty(ArrayCache::class, 'data');
$this->cacheDataReflection->setAccessible(true);
$this->useModelSet('cms');
parent::setUp();
}
private function getCacheSize(ArrayCache $cache): int
{
return count($this->cacheDataReflection->getValue($cache));
}
public function testQueryCacheDependsOnHints(): Query
public function testQueryCacheDependsOnHints(): array
{
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache();
$query->setQueryCacheDriver($cache);
$cache = new ArrayAdapter();
$query->setQueryCacheDriver(DoctrineProvider::wrap($cache));
$query->getResult();
$this->assertEquals(1, $this->getCacheSize($cache));
self::assertCount(2, $cache->getValues());
$query->setHint('foo', 'bar');
$query->getResult();
$this->assertEquals(2, $this->getCacheSize($cache));
self::assertCount(3, $cache->getValues());
return $query;
return [$query, $cache];
}
/**
* @param <type> $query
*
* @depends testQueryCacheDependsOnHints
*/
public function testQueryCacheDependsOnFirstResult($query): void
public function testQueryCacheDependsOnFirstResult(array $previous): void
{
$cache = $query->getQueryCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $cache] = $previous;
assert($query instanceof Query);
assert($cache instanceof ArrayAdapter);
$cacheCount = count($cache->getValues());
$query->setFirstResult(10);
$query->setMaxResults(9999);
$query->getResult();
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
self::assertCount($cacheCount + 1, $cache->getValues());
}
/**
* @param <type> $query
*
* @depends testQueryCacheDependsOnHints
*/
public function testQueryCacheDependsOnMaxResults($query): void
public function testQueryCacheDependsOnMaxResults(array $previous): void
{
$cache = $query->getQueryCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $cache] = $previous;
assert($query instanceof Query);
assert($cache instanceof ArrayAdapter);
$cacheCount = count($cache->getValues());
$query->setMaxResults(10);
$query->getResult();
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
self::assertCount($cacheCount + 1, $cache->getValues());
}
/**
* @param <type> $query
*
* @depends testQueryCacheDependsOnHints
*/
public function testQueryCacheDependsOnHydrationMode($query): void
public function testQueryCacheDependsOnHydrationMode(array $previous): void
{
$cache = $query->getQueryCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $cache] = $previous;
assert($query instanceof Query);
assert($cache instanceof ArrayAdapter);
$cacheCount = count($cache->getValues());
$query->getArrayResult();
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
self::assertCount($cacheCount + 1, $cache->getValues());
}
public function testQueryCacheNoHitSaveParserResult(): void
{
$this->_em->getConfiguration()->setQueryCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setQueryCacheImpl($this->createMock(Cache::class));
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
@@ -128,7 +113,7 @@ class QueryCacheTest extends OrmFunctionalTestCase
public function testQueryCacheHitDoesNotSaveParserResult(): void
{
$this->_em->getConfiguration()->setQueryCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setQueryCacheImpl($this->createMock(Cache::class));
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
@@ -167,6 +152,6 @@ class QueryCacheTest extends OrmFunctionalTestCase
$query->setQueryCacheDriver($cache);
$users = $query->getResult();
$query->getResult();
}
}

View File

@@ -2,42 +2,27 @@
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\ORM\NativeQuery;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\Tests\Models\CMS\CmsArticle;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\OrmFunctionalTestCase;
use ReflectionProperty;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function class_exists;
use function assert;
use function count;
use function iterator_to_array;
/**
* ResultCacheTest
*/
class ResultCacheTest extends OrmFunctionalTestCase
{
/** @var ReflectionProperty */
private $cacheDataReflection;
protected function setUp(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Test only applies with doctrine/cache 1.x');
}
$this->cacheDataReflection = new ReflectionProperty(ArrayCache::class, 'data');
$this->cacheDataReflection->setAccessible(true);
$this->useModelSet('cms');
parent::setUp();
}
private function getCacheSize(ArrayCache $cache): int
{
return count($this->cacheDataReflection->getValue($cache));
parent::setUp();
}
public function testResultCache(): void
@@ -53,7 +38,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query->setResultCacheDriver($cache)->setResultCacheId('my_cache_id');
@@ -62,7 +47,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
$users = $query->getResult();
$this->assertTrue($cache->contains('my_cache_id'));
$this->assertEquals(1, count($users));
$this->assertCount(1, $users);
$this->assertEquals('Roman', $users[0]->name);
$this->_em->clear();
@@ -73,13 +58,13 @@ class ResultCacheTest extends OrmFunctionalTestCase
$users = $query2->getResult();
$this->assertTrue($cache->contains('my_cache_id'));
$this->assertEquals(1, count($users));
$this->assertCount(1, $users);
$this->assertEquals('Roman', $users[0]->name);
}
public function testSetResultCacheId(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->setResultCacheDriver($cache);
@@ -87,29 +72,29 @@ class ResultCacheTest extends OrmFunctionalTestCase
$this->assertFalse($cache->contains('testing_result_cache_id'));
$users = $query->getResult();
$query->getResult();
$this->assertTrue($cache->contains('testing_result_cache_id'));
}
public function testUseResultCacheTrue(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->useResultCache(true);
$query->setResultCacheDriver($cache);
$query->setResultCacheId('testing_result_cache_id');
$users = $query->getResult();
$query->getResult();
$this->assertTrue($cache->contains('testing_result_cache_id'));
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setResultCacheImpl($this->createMock(Cache::class));
}
public function testUseResultCacheFalse(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->setResultCacheDriver($cache);
@@ -119,7 +104,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
$this->assertFalse($cache->contains('testing_result_cache_id'));
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setResultCacheImpl($this->createMock(Cache::class));
}
/**
@@ -127,7 +112,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
*/
public function testUseResultCacheParams(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$sqlCount = count($this->_sqlLoggerStack->queries);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1');
@@ -161,7 +146,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
public function testEnableResultCache(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->enableResultCache();
@@ -171,12 +156,12 @@ class ResultCacheTest extends OrmFunctionalTestCase
$this->assertTrue($cache->contains('testing_result_cache_id'));
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setResultCacheImpl($this->createMock(Cache::class));
}
public function testEnableResultCacheWithIterable(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$expectedSQLCount = count($this->_sqlLoggerStack->queries) + 1;
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
@@ -205,7 +190,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
'Expected query to be cached'
);
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setResultCacheImpl($this->createMock(Cache::class));
}
/**
@@ -213,7 +198,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
*/
public function testEnableResultCacheParams(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$sqlCount = count($this->_sqlLoggerStack->queries);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux WHERE ux.id = ?1');
@@ -247,7 +232,7 @@ class ResultCacheTest extends OrmFunctionalTestCase
public function testDisableResultCache(): void
{
$cache = new ArrayCache();
$cache = DoctrineProvider::wrap(new ArrayAdapter());
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->setResultCacheDriver($cache);
@@ -257,13 +242,14 @@ class ResultCacheTest extends OrmFunctionalTestCase
$this->assertFalse($cache->contains('testing_result_cache_id'));
$this->_em->getConfiguration()->setResultCacheImpl(new ArrayCache());
$this->_em->getConfiguration()->setResultCacheImpl($this->createMock(Cache::class));
}
public function testNativeQueryResultCaching(): NativeQuery
public function testNativeQueryResultCaching(): array
{
$cache = new ArrayCache();
$rsm = new ResultSetMapping();
$adapter = new ArrayAdapter();
$cache = DoctrineProvider::wrap($adapter);
$rsm = new ResultSetMapping();
$rsm->addScalarResult('id', 'u', 'integer');
@@ -272,55 +258,64 @@ class ResultCacheTest extends OrmFunctionalTestCase
$query->setParameter(1, 10);
$query->setResultCacheDriver($cache)->enableResultCache();
$this->assertEquals(0, $this->getCacheSize($cache));
$this->assertCount(0, $adapter->getValues());
$query->getResult();
$this->assertEquals(1, $this->getCacheSize($cache));
$this->assertCount(2, $adapter->getValues());
return $query;
return [$query, $adapter];
}
/**
* @depends testNativeQueryResultCaching
*/
public function testResultCacheNotDependsOnQueryHints(NativeQuery $query): void
public function testResultCacheNotDependsOnQueryHints(array $previous): void
{
$cache = $query->getResultCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $adapter] = $previous;
assert($query instanceof NativeQuery);
assert($adapter instanceof ArrayAdapter);
$cacheCount = count($adapter->getValues());
$query->setHint('foo', 'bar');
$query->getResult();
$this->assertEquals($cacheCount, $this->getCacheSize($cache));
$this->assertCount($cacheCount, $adapter->getValues());
}
/**
* @depends testNativeQueryResultCaching
*/
public function testResultCacheDependsOnParameters(NativeQuery $query): void
public function testResultCacheDependsOnParameters(array $previous): void
{
$cache = $query->getResultCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $adapter] = $previous;
assert($query instanceof NativeQuery);
assert($adapter instanceof ArrayAdapter);
$cacheCount = count($adapter->getValues());
$query->setParameter(1, 50);
$query->getResult();
$this->assertEquals($cacheCount + 1, $this->getCacheSize($cache));
$this->assertCount($cacheCount + 1, $adapter->getValues());
}
/**
* @depends testNativeQueryResultCaching
*/
public function testResultCacheNotDependsOnHydrationMode(NativeQuery $query): void
public function testResultCacheNotDependsOnHydrationMode(array $previous): void
{
$cache = $query->getResultCacheDriver();
$cacheCount = $this->getCacheSize($cache);
[$query, $adapter] = $previous;
assert($query instanceof NativeQuery);
assert($adapter instanceof ArrayAdapter);
$cacheCount = count($adapter->getValues());
$this->assertNotEquals(Query::HYDRATE_ARRAY, $query->getHydrationMode());
$query->getArrayResult();
$this->assertEquals($cacheCount, $this->getCacheSize($cache));
$this->assertCount($cacheCount, $adapter->getValues());
}
/**
@@ -351,13 +346,13 @@ class ResultCacheTest extends OrmFunctionalTestCase
$query = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1');
$query->setParameter(1, $user1);
$cache = new ArrayCache();
$cache = new ArrayAdapter();
$query->setResultCacheDriver($cache)->enableResultCache();
$query->setResultCacheDriver(DoctrineProvider::wrap($cache))->enableResultCache();
$articles = $query->getResult();
$this->assertEquals(1, count($articles));
$this->assertCount(1, $articles);
$this->assertEquals('baz', $articles[0]->topic);
$this->_em->clear();
@@ -365,20 +360,20 @@ class ResultCacheTest extends OrmFunctionalTestCase
$query2 = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1');
$query2->setParameter(1, $user1);
$query2->setResultCacheDriver($cache)->enableResultCache();
$query2->setResultCacheDriver(DoctrineProvider::wrap($cache))->enableResultCache();
$articles = $query2->getResult();
$this->assertEquals(1, count($articles));
$this->assertCount(1, $articles);
$this->assertEquals('baz', $articles[0]->topic);
$query3 = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.user = ?1');
$query3->setParameter(1, $user2);
$query3->setResultCacheDriver($cache)->enableResultCache();
$query3->setResultCacheDriver(DoctrineProvider::wrap($cache))->enableResultCache();
$articles = $query3->getResult();
$this->assertEquals(0, count($articles));
$this->assertCount(0, $articles);
}
}

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Configuration;
@@ -30,9 +30,8 @@ use Doctrine\Tests\Models\Company\CompanyPerson;
use Doctrine\Tests\OrmFunctionalTestCase;
use InvalidArgumentException;
use ReflectionMethod;
use ReflectionProperty;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function class_exists;
use function count;
use function in_array;
use function serialize;
@@ -397,31 +396,24 @@ class SQLFilterTest extends OrmFunctionalTestCase
public function testQueryCacheDependsOnFilters(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Test only applies with doctrine/cache 1.x');
}
$cacheDataReflection = new ReflectionProperty(ArrayCache::class, 'data');
$cacheDataReflection->setAccessible(true);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache();
$query->setQueryCacheDriver($cache);
$cache = new ArrayAdapter();
$query->setQueryCacheDriver(DoctrineProvider::wrap($cache));
$query->getResult();
$this->assertEquals(1, count($cacheDataReflection->getValue($cache)));
$this->assertCount(2, $cache->getValues());
$conf = $this->_em->getConfiguration();
$conf->addFilter('locale', '\Doctrine\Tests\ORM\Functional\MyLocaleFilter');
$conf->addFilter('locale', MyLocaleFilter::class);
$this->_em->getFilters()->enable('locale');
$query->getResult();
$this->assertEquals(2, count($cacheDataReflection->getValue($cache)));
$this->assertCount(3, $cache->getValues());
// Another time doesn't add another cache entry
$query->getResult();
$this->assertEquals(2, count($cacheDataReflection->getValue($cache)));
$this->assertCount(3, $cache->getValues());
}
public function testQueryGenerationDependsOnFilters(): void

View File

@@ -5,12 +5,14 @@ declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmFunctionalTestCase;
use Generator;
class DDC309Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->_schemaTool->createSchema(
[
$this->_em->getClassMetadata(DDC309Country::class),
@@ -19,6 +21,18 @@ class DDC309Test extends OrmFunctionalTestCase
);
}
protected function tearDown(): void
{
$this->_schemaTool->dropSchema(
[
$this->_em->getClassMetadata(DDC309Country::class),
$this->_em->getClassMetadata(DDC309User::class),
]
);
parent::tearDown();
}
public function testTwoIterateHydrations(): void
{
$c1 = new DDC309Country();
@@ -48,6 +62,57 @@ class DDC309Test extends OrmFunctionalTestCase
$this->assertEquals(2, $c[0]->id);
$this->assertEquals(2, $u[0]->id);
do {
$q->next();
} while ($q->valid());
do {
$r->next();
} while ($r->valid());
}
public function testTwoToIterableHydrations(): void
{
$c1 = new DDC309Country();
$c2 = new DDC309Country();
$u1 = new DDC309User();
$u2 = new DDC309User();
$this->_em->persist($c1);
$this->_em->persist($c2);
$this->_em->persist($u1);
$this->_em->persist($u2);
$this->_em->flush();
$this->_em->clear();
/** @var Generator<int, DDC309Country> $q */
$q = $this->_em->createQuery('SELECT c FROM Doctrine\Tests\ORM\Functional\Ticket\DDC309Country c')->toIterable();
$c = $q->current();
$this->assertEquals(1, $c->id);
/** @var Generator<int, DDC309User> $r */
$r = $this->_em->createQuery('SELECT u FROM Doctrine\Tests\ORM\Functional\Ticket\DDC309User u')->toIterable();
$u = $r->current();
$this->assertEquals(1, $u->id);
$q->next();
$r->next();
$c = $q->current();
$u = $r->current();
$this->assertEquals(2, $c->id);
$this->assertEquals(2, $u->id);
do {
$q->next();
} while ($q->valid());
do {
$r->next();
} while ($r->valid());
}
}

View File

@@ -50,7 +50,9 @@ final class GH7941Test extends OrmFunctionalTestCase
$result = $query->getSingleResult();
self::assertSame(6, $result['count']);
self::assertSame('325', $result['sales']);
// While other drivers will return a string, pdo_sqlite returns an integer as of PHP 8.1
self::assertEquals(325, $result['sales']);
// Driver return type and precision is determined by the underlying php extension, most seem to return a string.
// pdo_mysql and mysqli both currently return '54.1667' so this is the maximum precision we can assert.
@@ -68,7 +70,7 @@ final class GH7941Test extends OrmFunctionalTestCase
foreach ($query->getResult() as $i => $item) {
$product = self::PRODUCTS[$i];
self::assertSame(ltrim($product['price'], '-'), $item['absolute']);
self::assertEquals(ltrim($product['price'], '-'), $item['absolute']);
self::assertSame(strlen($product['name']), $item['length']);
// Driver return types for the `square_root` column are inconsistent depending on the underlying

View File

@@ -0,0 +1,55 @@
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\DBAL\LockMode;
use Doctrine\Tests\OrmFunctionalTestCase;
class GH8663Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->_schemaTool->createSchema([
$this->_em->getClassMetadata(GH8663VersionedEntity::class),
]);
}
protected function tearDown(): void
{
$this->_schemaTool->dropSchema([
$this->_em->getClassMetadata(GH8663VersionedEntity::class),
]);
parent::tearDown();
}
public function testDeletedEntity(): void
{
$result = $this->_em->find(GH8663VersionedEntity::class, 1, LockMode::OPTIMISTIC);
$this->assertNull($result);
}
}
/**
* @Entity
*/
class GH8663VersionedEntity
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue
* @var int
*/
protected $id;
/**
* @Version
* @Column(type="integer")
* @var int
*/
protected $version;
}

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Tests\OrmTestCase;
use function assert;
use function count;
final class GH8914Test extends OrmTestCase
{
/**
* @group GH-8914
* @doesNotPerformAssertions
*/
public function testDiscriminatorMapWithSeveralLevelsIsSupported(): void
{
$entityManager = $this->getTestEntityManager();
$entityManager->getClassMetadata(GH8914Person::class);
}
}
/**
* @MappedSuperclass
*/
abstract class GH8914BaseEntity
{
}
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="discr", type="string")
* @DiscriminatorMap({"person" = "GH8914Person", "employee" = "GH8914Employee"})
*/
class GH8914Person extends GH8914BaseEntity
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
public $id;
}
/**
* @Entity
*/
class GH8914Employee extends GH8914Person
{
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Tests\OrmFunctionalTestCase;
class GH9027Test extends OrmFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
$this->_schemaTool->createSchema([
$this->_em->getClassMetadata(GH9027Cart::class),
$this->_em->getClassMetadata(GH9027Customer::class),
]);
}
protected function tearDown(): void
{
$this->_schemaTool->dropSchema([
$this->_em->getClassMetadata(GH9027Cart::class),
$this->_em->getClassMetadata(GH9027Customer::class),
]);
parent::tearDown();
}
/**
* @group GH-9027
*/
public function testUnitOfWorkHandlesNullRelations(): void
{
$uow = new UnitOfWork($this->_em);
$hints = ['fetchMode' => [GH9027Cart::class => ['customer' => ClassMetadata::FETCH_EAGER]]];
$cart = $uow->createEntity(
GH9027Cart::class,
['id' => 1, 'customer' => 24252],
$hints
);
$this->assertEquals(null, $cart->customer);
}
}
/** @Entity */
class GH9027Customer
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
public $id;
/**
* @var GH9027Cart
* @OneToOne(targetEntity="GH9027Cart", mappedBy="customer")
*/
public $cart;
}
/** @Entity */
class GH9027Cart
{
/**
* @var int
* @Id
* @Column(type="integer")
* @GeneratedValue
*/
public $id;
/**
* @var GH9027Customer
* @OneToOne(targetEntity="GH9027Customer", inversedBy="cart")
* @JoinColumn(name="customer", referencedColumnName="id")
*/
public $customer;
}

View File

@@ -6,6 +6,7 @@ namespace Doctrine\Tests\ORM\Query;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Types\Type;
@@ -533,4 +534,25 @@ class QueryTest extends OrmTestCase
self::assertSame('Benjamin', $query->getParameter(':name')->getValue());
self::assertSame('Benjamin', $query->getParameter('name')->getValue());
}
public function testGetQueryCacheDriverWithDefaults(): void
{
$cache = $this->createMock(Cache::class);
$this->entityManager->getConfiguration()->setQueryCacheImpl($cache);
$query = $this->entityManager->createQuery('select u from ' . CmsUser::class . ' u');
self::assertSame($cache, $query->getQueryCacheDriver());
}
public function testGetQueryCacheDriverWithCacheExplicitlySet(): void
{
$cache = $this->createMock(Cache::class);
$query = $this->entityManager
->createQuery('select u from ' . CmsUser::class . ' u')
->setQueryCacheDriver($cache);
self::assertSame($cache, $query->getQueryCacheDriver());
}
}

View File

@@ -9,6 +9,7 @@ use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Cache;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\ORM\QueryBuilder;
@@ -149,6 +150,37 @@ class QueryBuilderTest extends OrmTestCase
);
}
public function testComplexInnerJoinWithComparisonCondition(): void
{
$qb = $this->entityManager->createQueryBuilder();
$qb
->select('u', 'a')
->from(CmsUser::class, 'u')
->innerJoin('u.articles', 'a', Join::ON, $qb->expr()->eq('u.id', 'a.author_id'));
$this->assertValidQueryBuilder(
$qb,
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id'
);
}
public function testComplexInnerJoinWithCompositeCondition(): void
{
$qb = $this->entityManager->createQueryBuilder();
$qb
->select('u', 'a')
->from(CmsUser::class, 'u')
->innerJoin('u.articles', 'a', Join::ON, $qb->expr()->andX(
$qb->expr()->eq('u.id', 'a.author_id'),
$qb->expr()->isNotNull('u.name')
));
$this->assertValidQueryBuilder(
$qb,
'SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a ON u.id = a.author_id AND u.name IS NOT NULL'
);
}
public function testComplexInnerJoinWithIndexBy(): void
{
$qb = $this->entityManager->createQueryBuilder()

View File

@@ -199,6 +199,46 @@ class SchemaValidatorTest extends OrmTestCase
$ce
);
}
/**
* @group 8771
*/
public function testMappedSuperclassNotPresentInDiscriminator(): void
{
$class1 = $this->em->getClassMetadata(MappedSuperclassEntity::class);
$ce = $this->validator->validateClass($class1);
$this->assertEquals([], $ce);
}
}
/**
* @MappedSuperclass
*/
abstract class MappedSuperclassEntity extends ParentEntity
{
}
/**
* @Entity
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorMap({"child" = ChildEntity::class})
*/
abstract class ParentEntity
{
/**
* @var mixed
* @Id
* @Column
*/
protected $key;
}
/**
* @Entity
*/
class ChildEntity extends MappedSuperclassEntity
{
}
/**

View File

@@ -12,11 +12,9 @@ use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\Mapping\Driver\XmlDriver;
use Doctrine\ORM\Mapping\Driver\YamlDriver;
use Doctrine\ORM\Tools\Setup;
use Doctrine\Tests\Common\Cache\ArrayCache;
use Doctrine\Tests\OrmTestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use function class_exists;
use function count;
use function get_include_path;
use function method_exists;
@@ -93,11 +91,7 @@ class SetupTest extends OrmTestCase
*/
public function testCacheNamespaceShouldBeGeneratedWhenCacheIsGivenButHasNoNamespace(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Only applies when using doctrine/cache directly');
}
$config = Setup::createConfiguration(false, '/foo', new ArrayCache());
$config = Setup::createConfiguration(false, '/foo', DoctrineProvider::wrap(new ArrayAdapter()));
$cache = $config->getMetadataCacheImpl();
self::assertSame('dc2_1effb2475fcfba4f9e8b8a1dbc8f3caf_', $cache->getNamespace());
@@ -108,11 +102,7 @@ class SetupTest extends OrmTestCase
*/
public function testConfiguredCacheNamespaceShouldBeUsedAsPrefixOfGeneratedNamespace(): void
{
if (! class_exists(ArrayCache::class)) {
$this->markTestSkipped('Only applies when using doctrine/cache directly');
}
$originalCache = new ArrayCache();
$originalCache = DoctrineProvider::wrap(new ArrayAdapter());
$originalCache->setNamespace('foo');
$config = Setup::createConfiguration(false, '/foo', $originalCache);

View File

@@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Tests;
use InvalidArgumentException;
use function is_int;
use function microtime;
use function sprintf;
/**
* Description of DoctrinePerformanceTestCase.
*/
class OrmPerformanceTestCase extends OrmFunctionalTestCase
{
/** @var int */
protected $maxRunningTime = 0;
protected function runTest(): void
{
$s = microtime(true);
parent::runTest();
$time = microtime(true) - $s;
if ($this->maxRunningTime !== 0 && $time > $this->maxRunningTime) {
$this->fail(
sprintf(
'expected running time: <= %s but was: %s',
$this->maxRunningTime,
$time
)
);
}
}
/**
* @throws InvalidArgumentException
*/
public function setMaxRunningTime(int $maxRunningTime): void
{
if (is_int($maxRunningTime) && $maxRunningTime >= 0) {
$this->maxRunningTime = $maxRunningTime;
} else {
throw new InvalidArgumentException();
}
}
public function getMaxRunningTime(): int
{
return $this->maxRunningTime;
}
}