From e487b6fe2b39f6ad8ae5760588a7c82b53ba5df0 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 10 Jan 2022 23:09:02 +0100 Subject: [PATCH 1/5] Relax assertion to include null as possible outcome (#9355) --- lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php index c4cb36431f2..b134632817c 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataFactory.php @@ -95,7 +95,7 @@ protected function onNotFoundMetadata($className) $this->evm->dispatchEvent(Events::onClassMetadataNotFound, $eventArgs); $classMetadata = $eventArgs->getFoundMetadata(); - assert($classMetadata instanceof ClassMetadata); + assert($classMetadata instanceof ClassMetadata || $classMetadata === null); return $classMetadata; } From 697e23422ffd8714aefbfe4f69a5f75c97beeeb3 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 10 Jan 2022 23:42:26 +0100 Subject: [PATCH 2/5] Remove the composer/package-versions-deprecated package --- UPGRADE.md | 3 +-- composer.json | 4 ++-- lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php | 8 ++++++-- .../Tests/ORM/Tools/Console/ConsoleRunnerTest.php | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 7c3da635ebf..1d7da3c95ed 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -228,8 +228,7 @@ These methods have been deprecated: ## Deprecated `Doctrine\ORM\Version` The `Doctrine\ORM\Version` class is now deprecated and will be removed in Doctrine ORM 3.0: -please refrain from checking the ORM version at runtime or use -[ocramius/package-versions](https://github.com/Ocramius/PackageVersions/). +please refrain from checking the ORM version at runtime or use Composer's [runtime API](https://getcomposer.org/doc/07-runtime.md#knowing-whether-package-x-is-installed-in-version-y). ## Deprecated `EntityManager#merge()` method diff --git a/composer.json b/composer.json index 155487dcffe..afd84e3965e 100644 --- a/composer.json +++ b/composer.json @@ -20,10 +20,10 @@ "sort-packages": true }, "require": { - "php": "^7.1 ||^8.0", + "php": "^7.1 || ^8.0", + "composer-runtime-api": "^2", "ext-ctype": "*", "ext-pdo": "*", - "composer/package-versions-deprecated": "^1.8", "doctrine/cache": "^1.12.1 || ^2.1.1", "doctrine/collections": "^1.5", "doctrine/common": "^3.0.3", diff --git a/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php b/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php index e9bc4bce6ab..2dce0ebbb4e 100644 --- a/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php +++ b/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php @@ -4,17 +4,18 @@ namespace Doctrine\ORM\Tools\Console; +use Composer\InstalledVersions; use Doctrine\DBAL\Tools\Console as DBALConsole; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Tools\Console\EntityManagerProvider\ConnectionFromManagerProvider; use Doctrine\ORM\Tools\Console\EntityManagerProvider\HelperSetManagerProvider; use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper; use OutOfBoundsException; -use PackageVersions\Versions; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command as SymfonyCommand; use Symfony\Component\Console\Helper\HelperSet; +use function assert; use function class_exists; /** @@ -59,7 +60,10 @@ public static function run($helperSetOrProvider, array $commands = []): void */ public static function createApplication($helperSetOrProvider, array $commands = []): Application { - $cli = new Application('Doctrine Command Line Interface', Versions::getVersion('doctrine/orm')); + $version = InstalledVersions::getVersion('doctrine/orm'); + assert($version !== null); + + $cli = new Application('Doctrine Command Line Interface', $version); $cli->setCatchExceptions(true); if ($helperSetOrProvider instanceof HelperSet) { diff --git a/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php b/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php index 9a0984b9b65..890f440d3e7 100644 --- a/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/Console/ConsoleRunnerTest.php @@ -4,11 +4,11 @@ namespace Doctrine\Tests\ORM\Tools\Console; +use Composer\InstalledVersions; use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; use Doctrine\ORM\Tools\Console\ConsoleRunner; use Doctrine\ORM\Tools\Console\EntityManagerProvider; use Doctrine\Tests\DoctrineTestCase; -use PackageVersions\Versions; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\HelperSet; @@ -28,7 +28,7 @@ public function testCreateApplicationShouldReturnAnApplicationWithTheCorrectComm $app = ConsoleRunner::createApplication($helperSet); self::assertSame($helperSet, $app->getHelperSet()); - self::assertSame(Versions::getVersion('doctrine/orm'), $app->getVersion()); + self::assertSame(InstalledVersions::getVersion('doctrine/orm'), $app->getVersion()); self::assertTrue($app->has('dbal:reserved-words')); self::assertTrue($app->has('dbal:run-sql')); From e369cb6e73f7f6cd2f8fb6c977e1566ed273ca59 Mon Sep 17 00:00:00 2001 From: Christian Mehldau Date: Wed, 12 Jan 2022 08:06:11 +0100 Subject: [PATCH 3/5] Generated/Virtual Columns: Insertable / Updateable (#9118) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Generated/Virtual Columns: Insertable / Updateable Defines whether a column is included in an SQL INSERT and/or UPDATE statement. Throws an exception for UPDATE statements attempting to update this field/column. Closes #5728 * Apply suggestions from code review Co-authored-by: Grégoire Paris * Add example for virtual column usage in attributes to docs. Co-authored-by: Benjamin Eberlei Co-authored-by: Grégoire Paris --- docs/en/reference/annotations-reference.rst | 19 +++++ docs/en/reference/attributes-reference.rst | 21 +++++ docs/en/reference/basic-mapping.rst | 4 + docs/en/reference/xml-mapping.rst | 5 ++ doctrine-mapping.xsd | 13 +++ .../ORM/Cache/DefaultEntityHydrator.php | 12 ++- .../ORM/Mapping/Builder/FieldBuilder.php | 28 +++++++ .../ORM/Mapping/ClassMetadataInfo.php | 61 +++++++++++++- lib/Doctrine/ORM/Mapping/Column.php | 22 ++++- .../ORM/Mapping/Driver/AnnotationDriver.php | 45 ++++++++-- .../ORM/Mapping/Driver/AttributeDriver.php | 26 ++++++ lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php | 14 ++++ .../ORM/Mapping/Driver/YamlDriver.php | 18 ++++ lib/Doctrine/ORM/Mapping/MappingException.php | 5 ++ .../Entity/BasicEntityPersister.php | 82 +++++++++++++------ .../Entity/JoinedSubclassPersister.php | 29 ++++--- .../ORM/Tools/Export/Driver/XmlExporter.php | 8 ++ phpstan-baseline.neon | 12 +-- .../Tests/Models/Upsertable/Insertable.php | 74 +++++++++++++++++ .../Tests/Models/Upsertable/Updatable.php | 72 ++++++++++++++++ .../Functional/InsertableUpdateableTest.php | 74 +++++++++++++++++ .../ORM/Mapping/AbstractMappingDriverTest.php | 26 ++++++ .../Tests/ORM/Mapping/ClassMetadataTest.php | 4 + ...ine.Tests.Models.Upsertable.Insertable.php | 29 +++++++ ...rine.Tests.Models.Upsertable.Updatable.php | 28 +++++++ ...Tests.Models.Upsertable.Insertable.dcm.xml | 16 ++++ ....Tests.Models.Upsertable.Updatable.dcm.xml | 16 ++++ ...Tests.Models.Upsertable.Insertable.dcm.yml | 17 ++++ ....Tests.Models.Upsertable.Updatable.dcm.yml | 17 ++++ 29 files changed, 737 insertions(+), 60 deletions(-) create mode 100644 tests/Doctrine/Tests/Models/Upsertable/Insertable.php create mode 100644 tests/Doctrine/Tests/Models/Upsertable/Updatable.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/InsertableUpdateableTest.php create mode 100644 tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Insertable.php create mode 100644 tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Updatable.php create mode 100644 tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.xml create mode 100644 tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.xml create mode 100644 tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.yml create mode 100644 tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.yml diff --git a/docs/en/reference/annotations-reference.rst b/docs/en/reference/annotations-reference.rst index 226842d71a4..24ce6a5e87c 100644 --- a/docs/en/reference/annotations-reference.rst +++ b/docs/en/reference/annotations-reference.rst @@ -123,6 +123,18 @@ Optional attributes: - **nullable**: Determines if NULL values allowed for this column. If not specified, default value is false. +- **insertable**: Boolean value to determine if the column should be + included when inserting a new row into the underlying entities table. + If not specified, default value is true. + +- **updatable**: Boolean value to determine if the column should be + included when updating the row of the underlying entities table. + If not specified, default value is true. + +- **generated**: An enum with the possible values ALWAYS, INSERT, NEVER. Is + used after an INSERT or UPDATE statement to determine if the database + generated this value and it needs to be fetched using a SELECT statement. + - **options**: Array of additional options: - ``default``: The default value to set for the column if no value @@ -193,6 +205,13 @@ Examples: */ protected $loginCount; + /** + * Generated column + * @Column(type="string", name="user_fullname", insertable=false, updatable=false) + * MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)), + */ + protected $fullname; + .. _annref_column_result: @ColumnResult diff --git a/docs/en/reference/attributes-reference.rst b/docs/en/reference/attributes-reference.rst index 89b1f8cad33..ce781220aff 100644 --- a/docs/en/reference/attributes-reference.rst +++ b/docs/en/reference/attributes-reference.rst @@ -178,6 +178,18 @@ Optional parameters: - **nullable**: Determines if NULL values allowed for this column. If not specified, default value is ``false``. +- **insertable**: Boolean value to determine if the column should be + included when inserting a new row into the underlying entities table. + If not specified, default value is true. + +- **updatable**: Boolean value to determine if the column should be + included when updating the row of the underlying entities table. + If not specified, default value is true. + +- **generated**: An enum with the possible values ALWAYS, INSERT, NEVER. Is + used after an INSERT or UPDATE statement to determine if the database + generated this value and it needs to be fetched using a SELECT statement. + - **options**: Array of additional options: - ``default``: The default value to set for the column if no value @@ -248,6 +260,15 @@ Examples: )] protected $loginCount; + // MySQL example: full_name char(41) GENERATED ALWAYS AS (concat(firstname,' ',lastname)), + #[Column( + type: "string", + name: "user_fullname", + insertable: false, + updatable: false + )] + protected $fullname; + .. _attrref_cache: #[Cache] diff --git a/docs/en/reference/basic-mapping.rst b/docs/en/reference/basic-mapping.rst index b613f9d6386..b17a968e3d3 100644 --- a/docs/en/reference/basic-mapping.rst +++ b/docs/en/reference/basic-mapping.rst @@ -199,6 +199,10 @@ list: unique key. - ``nullable``: (optional, default FALSE) Whether the database column is nullable. +- ``insertable``: (optional, default TRUE) Whether the database + column should be inserted. +- ``updatable``: (optional, default TRUE) Whether the database + column should be updated. - ``enumType``: (optional, requires PHP 8.1 and ORM 2.11) The PHP enum type name to convert the database value into. - ``precision``: (optional, default 0) The precision for a decimal diff --git a/docs/en/reference/xml-mapping.rst b/docs/en/reference/xml-mapping.rst index 35856e6fd56..39e637a945c 100644 --- a/docs/en/reference/xml-mapping.rst +++ b/docs/en/reference/xml-mapping.rst @@ -256,6 +256,11 @@ Optional attributes: table? Defaults to false. - nullable - Should this field allow NULL as a value? Defaults to false. +- insertable - Should this field be inserted? Defaults to true. +- updatable - Should this field be updated? Defaults to true. +- generated - Enum of the values ALWAYS, INSERT, NEVER that determines if + generated value must be fetched from database after INSERT or UPDATE. + Defaults to "NEVER". - version - Should this field be used for optimistic locking? Only works on fields with type integer or datetime. - scale - Scale of a decimal type. diff --git a/doctrine-mapping.xsd b/doctrine-mapping.xsd index 142f204ae35..db7f4311134 100644 --- a/doctrine-mapping.xsd +++ b/doctrine-mapping.xsd @@ -288,6 +288,14 @@ + + + + + + + + @@ -299,6 +307,9 @@ + + + @@ -623,6 +634,8 @@ + + diff --git a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php index aaba02d067f..384664fa5e6 100644 --- a/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php +++ b/lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php @@ -55,8 +55,16 @@ public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $e $data = $this->uow->getOriginalEntityData($entity); $data = array_merge($data, $metadata->getIdentifierValues($entity)); // why update has no identifier values ? - if ($metadata->isVersioned) { - $data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField); + if ($metadata->requiresFetchAfterChange) { + if ($metadata->isVersioned) { + $data[$metadata->versionField] = $metadata->getFieldValue($entity, $metadata->versionField); + } + + foreach ($metadata->fieldMappings as $name => $fieldMapping) { + if (isset($fieldMapping['generated'])) { + $data[$name] = $metadata->getFieldValue($entity, $name); + } + } } foreach ($metadata->associationMappings as $name => $assoc) { diff --git a/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php b/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php index 8b9e62d548a..f6d2db6c70e 100644 --- a/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php +++ b/lib/Doctrine/ORM/Mapping/Builder/FieldBuilder.php @@ -110,6 +110,34 @@ public function precision($p) return $this; } + /** + * Sets insertable. + * + * @return $this + */ + public function insertable(bool $flag = true): self + { + if (! $flag) { + $this->mapping['notInsertable'] = true; + } + + return $this; + } + + /** + * Sets updatable. + * + * @return $this + */ + public function updatable(bool $flag = true): self + { + if (! $flag) { + $this->mapping['notUpdatable'] = true; + } + + return $this; + } + /** * Sets scale. * diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index c95461030bd..ab4b97cfe86 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -80,6 +80,9 @@ * length?: int, * id?: bool, * nullable?: bool, + * notInsertable?: bool, + * notUpdatable?: bool, + * generated?: string, * enumType?: class-string, * columnDefinition?: string, * precision?: int, @@ -258,6 +261,21 @@ class ClassMetadataInfo implements ClassMetadata */ public const CACHE_USAGE_READ_WRITE = 3; + /** + * The value of this column is never generated by the database. + */ + public const GENERATED_NEVER = 0; + + /** + * The value of this column is generated by the database on INSERT, but not on UPDATE. + */ + public const GENERATED_INSERT = 1; + + /** + * The value of this column is generated by the database on both INSERT and UDPATE statements. + */ + public const GENERATED_ALWAYS = 2; + /** * READ-ONLY: The name of the entity class. * @@ -439,6 +457,12 @@ class ClassMetadataInfo implements ClassMetadata * - nullable (boolean, optional) * Whether the column is nullable. Defaults to FALSE. * + * - 'notInsertable' (boolean, optional) + * Whether the column is not insertable. Optional. Is only set if value is TRUE. + * + * - 'notUpdatable' (boolean, optional) + * Whether the column is updatable. Optional. Is only set if value is TRUE. + * * - columnDefinition (string, optional, schema-only) * The SQL fragment that is used when generating the DDL for the column. * @@ -659,13 +683,21 @@ class ClassMetadataInfo implements ClassMetadata */ public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT; + /** + * READ-ONLY: A Flag indicating whether one or more columns of this class + * have to be reloaded after insert / update operations. + * + * @var bool + */ + public $requiresFetchAfterChange = false; + /** * READ-ONLY: A flag for whether or not instances of this class are to be versioned * with optimistic locking. * * @var bool */ - public $isVersioned; + public $isVersioned = false; /** * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any). @@ -963,6 +995,10 @@ public function __sleep() $serialized[] = 'cache'; } + if ($this->requiresFetchAfterChange) { + $serialized[] = 'requiresFetchAfterChange'; + } + return $serialized; } @@ -1611,6 +1647,16 @@ protected function validateAndCompleteFieldMapping(array $mapping): array $mapping['requireSQLConversion'] = true; } + if (isset($mapping['generated'])) { + if (! in_array($mapping['generated'], [self::GENERATED_NEVER, self::GENERATED_INSERT, self::GENERATED_ALWAYS])) { + throw MappingException::invalidGeneratedMode($mapping['generated']); + } + + if ($mapping['generated'] === self::GENERATED_NEVER) { + unset($mapping['generated']); + } + } + if (isset($mapping['enumType'])) { if (PHP_VERSION_ID < 80100) { throw MappingException::enumsRequirePhp81($this->name, $mapping['fieldName']); @@ -2675,6 +2721,10 @@ public function mapField(array $mapping) $mapping = $this->validateAndCompleteFieldMapping($mapping); $this->assertFieldNotMapped($mapping['fieldName']); + if (isset($mapping['generated'])) { + $this->requiresFetchAfterChange = true; + } + $this->fieldMappings[$mapping['fieldName']] = $mapping; } @@ -3405,8 +3455,9 @@ public function setSequenceGeneratorDefinition(array $definition) */ public function setVersionMapping(array &$mapping) { - $this->isVersioned = true; - $this->versionField = $mapping['fieldName']; + $this->isVersioned = true; + $this->versionField = $mapping['fieldName']; + $this->requiresFetchAfterChange = true; if (! isset($mapping['default'])) { if (in_array($mapping['type'], ['integer', 'bigint', 'smallint'], true)) { @@ -3429,6 +3480,10 @@ public function setVersionMapping(array &$mapping) public function setVersioned($bool) { $this->isVersioned = $bool; + + if ($bool) { + $this->requiresFetchAfterChange = true; + } } /** diff --git a/lib/Doctrine/ORM/Mapping/Column.php b/lib/Doctrine/ORM/Mapping/Column.php index b90a80ff941..f799bd9bccd 100644 --- a/lib/Doctrine/ORM/Mapping/Column.php +++ b/lib/Doctrine/ORM/Mapping/Column.php @@ -44,6 +44,12 @@ final class Column implements Annotation /** @var bool */ public $nullable = false; + /** @var bool */ + public $insertable = true; + + /** @var bool */ + public $updatable = true; + /** @var class-string<\BackedEnum>|null */ public $enumType = null; @@ -53,9 +59,17 @@ final class Column implements Annotation /** @var string|null */ public $columnDefinition; + /** + * @var string|null + * @psalm-var 'NEVER'|'INSERT'|'ALWAYS'|null + * @Enum({"NEVER", "INSERT", "ALWAYS"}) + */ + public $generated; + /** * @param class-string<\BackedEnum>|null $enumType * @param array $options + * @psalm-param 'NEVER'|'INSERT'|'ALWAYS'|null $generated */ public function __construct( ?string $name = null, @@ -65,9 +79,12 @@ public function __construct( ?int $scale = null, bool $unique = false, bool $nullable = false, + bool $insertable = true, + bool $updatable = true, ?string $enumType = null, array $options = [], - ?string $columnDefinition = null + ?string $columnDefinition = null, + ?string $generated = null ) { $this->name = $name; $this->type = $type; @@ -76,8 +93,11 @@ public function __construct( $this->scale = $scale; $this->unique = $unique; $this->nullable = $nullable; + $this->insertable = $insertable; + $this->updatable = $updatable; $this->enumType = $enumType; $this->options = $options; $this->columnDefinition = $columnDefinition; + $this->generated = $generated; } } diff --git a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php index 5e6e169051c..bceef45da17 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php @@ -633,6 +633,22 @@ private function getFetchMode(string $className, string $fetchMode): int return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode); } + /** + * Attempts to resolve the generated mode. + * + * @psalm-return ClassMetadataInfo::GENERATED_* + * + * @throws MappingException If the fetch mode is not valid. + */ + private function getGeneratedMode(string $generatedMode): int + { + if (! defined('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode)) { + throw MappingException::invalidGeneratedMode($generatedMode); + } + + return constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode); + } + /** * Parses the given method. * @@ -718,6 +734,9 @@ private function joinColumnToArray(Mapping\JoinColumn $joinColumn): array * unique: bool, * nullable: bool, * precision: int, + * notInsertable?: bool, + * notUpdateble?: bool, + * generated?: ClassMetadataInfo::GENERATED_*, * enumType?: class-string, * options?: mixed[], * columnName?: string, @@ -727,15 +746,27 @@ private function joinColumnToArray(Mapping\JoinColumn $joinColumn): array private function columnToArray(string $fieldName, Mapping\Column $column): array { $mapping = [ - 'fieldName' => $fieldName, - 'type' => $column->type, - 'scale' => $column->scale, - 'length' => $column->length, - 'unique' => $column->unique, - 'nullable' => $column->nullable, - 'precision' => $column->precision, + 'fieldName' => $fieldName, + 'type' => $column->type, + 'scale' => $column->scale, + 'length' => $column->length, + 'unique' => $column->unique, + 'nullable' => $column->nullable, + 'precision' => $column->precision, ]; + if (! $column->insertable) { + $mapping['notInsertable'] = true; + } + + if (! $column->updatable) { + $mapping['notUpdatable'] = true; + } + + if ($column->generated) { + $mapping['generated'] = $this->getGeneratedMode($column->generated); + } + if ($column->options) { $mapping['options'] = $column->options; } diff --git a/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php index 6e0f3182ac1..3155fa753c9 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/AttributeDriver.php @@ -528,6 +528,20 @@ private function getFetchMode(string $className, string $fetchMode): int return constant('Doctrine\ORM\Mapping\ClassMetadata::FETCH_' . $fetchMode); } + /** + * Attempts to resolve the generated mode. + * + * @throws MappingException If the fetch mode is not valid. + */ + private function getGeneratedMode(string $generatedMode): int + { + if (! defined('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode)) { + throw MappingException::invalidGeneratedMode($generatedMode); + } + + return constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $generatedMode); + } + /** * Parses the given method. * @@ -644,6 +658,18 @@ private function columnToArray(string $fieldName, Mapping\Column $column): array $mapping['columnDefinition'] = $column->columnDefinition; } + if ($column->updatable === false) { + $mapping['notUpdatable'] = true; + } + + if ($column->insertable === false) { + $mapping['notInsertable'] = true; + } + + if ($column->generated !== null) { + $mapping['generated'] = $this->getGeneratedMode($column->generated); + } + if ($column->enumType) { $mapping['enumType'] = $column->enumType; } diff --git a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php index f6eba16a7f9..2d0cccd2efa 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php @@ -800,6 +800,8 @@ private function joinColumnToArray(SimpleXMLElement $joinColumnElement): array * scale?: int, * unique?: bool, * nullable?: bool, + * notInsertable?: bool, + * notUpdatable?: bool, * enumType?: string, * version?: bool, * columnDefinition?: string, @@ -840,6 +842,18 @@ private function columnToArray(SimpleXMLElement $fieldMapping): array $mapping['nullable'] = $this->evaluateBoolean($fieldMapping['nullable']); } + if (isset($fieldMapping['insertable']) && ! $this->evaluateBoolean($fieldMapping['insertable'])) { + $mapping['notInsertable'] = true; + } + + if (isset($fieldMapping['updatable']) && ! $this->evaluateBoolean($fieldMapping['updatable'])) { + $mapping['notUpdatable'] = true; + } + + if (isset($fieldMapping['generated'])) { + $mapping['generated'] = constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . (string) $fieldMapping['generated']); + } + if (isset($fieldMapping['version']) && $fieldMapping['version']) { $mapping['version'] = $this->evaluateBoolean($fieldMapping['version']); } diff --git a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php index 1eab5e87e4c..ff11dfbb7ca 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php @@ -786,6 +786,9 @@ private function joinColumnToArray(array $joinColumnElement): array * unique?: mixed, * options?: mixed, * nullable?: mixed, + * insertable?: mixed, + * updatable?: mixed, + * generated?: mixed, * enumType?: class-string, * version?: mixed, * columnDefinition?: mixed @@ -802,6 +805,9 @@ private function joinColumnToArray(array $joinColumnElement): array * unique?: bool, * options?: mixed, * nullable?: mixed, + * notInsertable?: mixed, + * notUpdatable?: mixed, + * generated?: mixed, * enumType?: class-string, * version?: mixed, * columnDefinition?: mixed @@ -850,6 +856,18 @@ private function columnToArray(string $fieldName, ?array $column): array $mapping['nullable'] = $column['nullable']; } + if (isset($column['insertable']) && ! (bool) $column['insertable']) { + $mapping['notInsertable'] = true; + } + + if (isset($column['updatable']) && ! (bool) $column['updatable']) { + $mapping['notUpdatable'] = true; + } + + if (isset($column['generated'])) { + $mapping['generated'] = constant('Doctrine\ORM\Mapping\ClassMetadata::GENERATED_' . $column['generated']); + } + if (isset($column['version']) && $column['version']) { $mapping['version'] = $column['version']; } diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index 3fdc026a41e..0ba7506dfd1 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -825,6 +825,11 @@ public static function invalidFetchMode($className, $annotation) return new self("Entity '" . $className . "' has a mapping with invalid fetch mode '" . $annotation . "'"); } + public static function invalidGeneratedMode(string $annotation): MappingException + { + return new self("Invalid generated mode '" . $annotation . "'"); + } + /** * @param string $className * diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index 4a32448fbc8..d9ac746adc1 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -30,8 +30,10 @@ use Doctrine\ORM\UnitOfWork; use Doctrine\ORM\Utility\IdentifierFlattener; use Doctrine\ORM\Utility\PersisterHelper; +use LengthException; use function array_combine; +use function array_keys; use function array_map; use function array_merge; use function array_search; @@ -284,8 +286,8 @@ public function executeInserts() $id = $this->class->getIdentifierValues($entity); } - if ($this->class->isVersioned) { - $this->assignDefaultVersionValue($entity, $id); + if ($this->class->requiresFetchAfterChange) { + $this->assignDefaultVersionAndUpsertableValues($entity, $id); } } @@ -297,50 +299,71 @@ public function executeInserts() /** * Retrieves the default version value which was created * by the preceding INSERT statement and assigns it back in to the - * entities version field. + * entities version field if the given entity is versioned. + * Also retrieves values of columns marked as 'non insertable' and / or + * 'not updatable' and assigns them back to the entities corresponding fields. * * @param object $entity * @param mixed[] $id * * @return void */ - protected function assignDefaultVersionValue($entity, array $id) + protected function assignDefaultVersionAndUpsertableValues($entity, array $id) { - $value = $this->fetchVersionValue($this->class, $id); + $values = $this->fetchVersionAndNotUpsertableValues($this->class, $id); - $this->class->setFieldValue($entity, $this->class->versionField, $value); + foreach ($values as $field => $value) { + $value = Type::getType($this->class->fieldMappings[$field]['type'])->convertToPHPValue($value, $this->platform); + + $this->class->setFieldValue($entity, $field, $value); + } } /** - * Fetches the current version value of a versioned entity. + * Fetches the current version value of a versioned entity and / or the values of fields + * marked as 'not insertable' and / or 'not updatable'. * * @param ClassMetadata $versionedClass * @param mixed[] $id * * @return mixed */ - protected function fetchVersionValue($versionedClass, array $id) + protected function fetchVersionAndNotUpsertableValues($versionedClass, array $id) { - $versionField = $versionedClass->versionField; - $fieldMapping = $versionedClass->fieldMappings[$versionField]; - $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); - $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform); - $columnName = $this->quoteStrategy->getColumnName($versionField, $versionedClass, $this->platform); + $columnNames = []; + foreach ($this->class->fieldMappings as $key => $column) { + if (isset($column['generated']) || ($this->class->isVersioned && $key === $versionedClass->versionField)) { + $columnNames[$key] = $this->quoteStrategy->getColumnName($key, $versionedClass, $this->platform); + } + } + + $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); + $identifier = $this->quoteStrategy->getIdentifierColumnNames($versionedClass, $this->platform); // FIXME: Order with composite keys might not be correct - $sql = 'SELECT ' . $columnName - . ' FROM ' . $tableName - . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; + $sql = 'SELECT ' . implode(', ', $columnNames) + . ' FROM ' . $tableName + . ' WHERE ' . implode(' = ? AND ', $identifier) . ' = ?'; $flatId = $this->identifierFlattener->flattenIdentifier($versionedClass, $id); - $value = $this->conn->fetchOne( + $values = $this->conn->fetchNumeric( $sql, array_values($flatId), $this->extractIdentifierTypes($id, $versionedClass) ); - return Type::getType($fieldMapping['type'])->convertToPHPValue($value, $this->platform); + if ($values === false) { + throw new LengthException('Unexpected empty result for database query.'); + } + + $values = array_combine(array_keys($columnNames), $values); + + if (! $values) { + throw new LengthException('Unexpected number of database columns.'); + } + + return $values; } /** @@ -383,10 +406,10 @@ public function update($entity) $this->updateTable($entity, $quotedTableName, $data, $isVersioned); - if ($isVersioned) { + if ($this->class->requiresFetchAfterChange) { $id = $this->class->getIdentifierValues($entity); - $this->assignDefaultVersionValue($entity, $id); + $this->assignDefaultVersionAndUpsertableValues($entity, $id); } } @@ -594,12 +617,13 @@ public function delete($entity) * ) * * - * @param object $entity The entity for which to prepare the data. + * @param object $entity The entity for which to prepare the data. + * @param bool $isInsert Whether the data to be prepared refers to an insert statement. * * @return mixed[][] The prepared data. * @psalm-return array> */ - protected function prepareUpdateData($entity) + protected function prepareUpdateData($entity, bool $isInsert = false) { $versionField = null; $result = []; @@ -625,6 +649,14 @@ protected function prepareUpdateData($entity) $fieldMapping = $this->class->fieldMappings[$field]; $columnName = $fieldMapping['columnName']; + if (! $isInsert && isset($fieldMapping['notUpdatable'])) { + continue; + } + + if ($isInsert && isset($fieldMapping['notInsertable'])) { + continue; + } + $this->columnTypes[$columnName] = $fieldMapping['type']; $result[$this->getOwningTable($field)][$columnName] = $newVal; @@ -692,7 +724,7 @@ protected function prepareUpdateData($entity) */ protected function prepareInsertData($entity) { - return $this->prepareUpdateData($entity); + return $this->prepareUpdateData($entity, true); } /** @@ -1440,6 +1472,10 @@ protected function getInsertColumnList() } if (! $this->class->isIdGeneratorIdentity() || $this->class->identifier[0] !== $name) { + if (isset($this->class->fieldMappings[$name]['notInsertable'])) { + continue; + } + $columns[] = $this->quoteStrategy->getColumnName($name, $this->class, $this->platform); $this->columnTypes[$name] = $this->class->fieldMappings[$name]['type']; } diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index 5c59168eb75..aa195d04aa9 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -6,6 +6,7 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Internal\SQLResultCasing; use Doctrine\ORM\Mapping\ClassMetadata; @@ -168,8 +169,8 @@ public function executeInserts() $id = $this->em->getUnitOfWork()->getEntityIdentifier($entity); } - if ($this->class->isVersioned) { - $this->assignDefaultVersionValue($entity, $id); + if ($this->class->requiresFetchAfterChange) { + $this->assignDefaultVersionAndUpsertableValues($entity, $id); } // Execute inserts on subtables. @@ -211,9 +212,6 @@ public function update($entity) } $isVersioned = $this->class->isVersioned; - if ($isVersioned === false) { - return; - } $versionedClass = $this->getVersionedClassMetadata(); $versionedTable = $versionedClass->getTableName(); @@ -225,10 +223,10 @@ public function update($entity) $this->updateTable($entity, $tableName, $data, $versioned); } - // Make sure the table with the version column is updated even if no columns on that - // table were affected. - if ($isVersioned) { - if (! isset($updateData[$versionedTable])) { + if ($this->class->requiresFetchAfterChange) { + // Make sure the table with the version column is updated even if no columns on that + // table were affected. + if ($isVersioned && ! isset($updateData[$versionedTable])) { $tableName = $this->quoteStrategy->getTableName($versionedClass, $this->platform); $this->updateTable($entity, $tableName, [], true); @@ -236,7 +234,7 @@ public function update($entity) $identifiers = $this->em->getUnitOfWork()->getEntityIdentifier($entity); - $this->assignDefaultVersionValue($entity, $identifiers); + $this->assignDefaultVersionAndUpsertableValues($entity, $identifiers); } } @@ -549,10 +547,15 @@ protected function getInsertColumnList() /** * {@inheritdoc} */ - protected function assignDefaultVersionValue($entity, array $id) + protected function assignDefaultVersionAndUpsertableValues($entity, array $id) { - $value = $this->fetchVersionValue($this->getVersionedClassMetadata(), $id); - $this->class->setFieldValue($entity, $this->class->versionField, $value); + $values = $this->fetchVersionAndNotUpsertableValues($this->getVersionedClassMetadata(), $id); + + foreach ($values as $field => $value) { + $value = Type::getType($this->class->fieldMappings[$field]['type'])->convertToPHPValue($value, $this->platform); + + $this->class->setFieldValue($entity, $field, $value); + } } private function getJoinSql(string $baseTableAlias): string diff --git a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php index 8c9ce6d7b92..11ef880ff7b 100644 --- a/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php +++ b/lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php @@ -215,6 +215,14 @@ public function exportClassMetadata(ClassMetadataInfo $metadata) if (isset($field['nullable'])) { $fieldXml->addAttribute('nullable', $field['nullable'] ? 'true' : 'false'); } + + if (isset($field['notInsertable'])) { + $fieldXml->addAttribute('insertable', 'false'); + } + + if (isset($field['notUpdatable'])) { + $fieldXml->addAttribute('updatable', 'false'); + } } } diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c4f54cca953..17ecb7083a1 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -760,16 +760,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php - - - message: "#^If condition is always true\\.$#" - count: 1 - path: lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php - - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php - - message: "#^Parameter \\#1 \\$em of method Doctrine\\\\ORM\\\\Id\\\\AbstractIdGenerator\\:\\:generate\\(\\) expects Doctrine\\\\ORM\\\\EntityManager, Doctrine\\\\ORM\\\\EntityManagerInterface given\\.$#" count: 1 @@ -1741,7 +1731,7 @@ parameters: path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php - - message: "#^Offset 'version' on array\\{type\\: string, fieldName\\: string, columnName\\: string, length\\?\\: int, id\\?\\: bool, nullable\\?\\: bool, enumType\\?\\: class\\-string\\, columnDefinition\\?\\: string, \\.\\.\\.\\} in isset\\(\\) does not exist\\.$#" + message: "#^Offset 'version' on array\\{type\\: string, fieldName\\: string, columnName\\: string, length\\?\\: int, id\\?\\: bool, nullable\\?\\: bool, notInsertable\\?\\: bool, notUpdatable\\?\\: bool, \\.\\.\\.\\} in isset\\(\\) does not exist\\.$#" count: 1 path: lib/Doctrine/ORM/Tools/Export/Driver/XmlExporter.php diff --git a/tests/Doctrine/Tests/Models/Upsertable/Insertable.php b/tests/Doctrine/Tests/Models/Upsertable/Insertable.php new file mode 100644 index 00000000000..3ebfc1a76ff --- /dev/null +++ b/tests/Doctrine/Tests/Models/Upsertable/Insertable.php @@ -0,0 +1,74 @@ + '1234'], generated: 'INSERT')] + public $nonInsertableContent; + + /** + * @var string + * @Column(type="string", insertable=true) + */ + #[Column(type: 'string', insertable: true)] + public $insertableContent; + + public static function loadMetadata(ClassMetadata $metadata): ClassMetadata + { + $metadata->setPrimaryTable( + ['name' => 'insertable_column'] + ); + + $metadata->mapField( + [ + 'id' => true, + 'fieldName' => 'id', + ] + ); + $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); + + $metadata->mapField( + [ + 'fieldName' => 'nonInsertableContent', + 'notInsertable' => true, + 'options' => ['default' => '1234'], + 'generated' => ClassMetadataInfo::GENERATED_INSERT, + ] + ); + $metadata->mapField( + ['fieldName' => 'insertableContent'] + ); + + return $metadata; + } +} diff --git a/tests/Doctrine/Tests/Models/Upsertable/Updatable.php b/tests/Doctrine/Tests/Models/Upsertable/Updatable.php new file mode 100644 index 00000000000..bd793773512 --- /dev/null +++ b/tests/Doctrine/Tests/Models/Upsertable/Updatable.php @@ -0,0 +1,72 @@ +setPrimaryTable( + ['name' => 'updatable_column'] + ); + + $metadata->mapField( + [ + 'id' => true, + 'fieldName' => 'id', + ] + ); + $metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_AUTO); + + $metadata->mapField( + [ + 'fieldName' => 'nonUpdatableContent', + 'notUpdatable' => true, + 'generated' => ClassMetadataInfo::GENERATED_ALWAYS, + ] + ); + $metadata->mapField( + ['fieldName' => 'updatableContent'] + ); + + return $metadata; + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/InsertableUpdateableTest.php b/tests/Doctrine/Tests/ORM/Functional/InsertableUpdateableTest.php new file mode 100644 index 00000000000..3c9d20d40b1 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/InsertableUpdateableTest.php @@ -0,0 +1,74 @@ +_schemaTool->createSchema( + [ + $this->_em->getClassMetadata(Updatable::class), + $this->_em->getClassMetadata(Insertable::class), + ] + ); + } catch (ToolsException $e) { + } + } + + public function testNotInsertableIsFetchedFromDatabase(): void + { + $insertable = new Insertable(); + $insertable->insertableContent = 'abcdefg'; + + $this->_em->persist($insertable); + $this->_em->flush(); + + // gets inserted from default value and fetches value from database + self::assertEquals('1234', $insertable->nonInsertableContent); + + $insertable->nonInsertableContent = '5678'; + + $this->_em->flush(); + $this->_em->clear(); + + $insertable = $this->_em->find(Insertable::class, $insertable->id); + + // during UPDATE statement it is not ignored + self::assertEquals('5678', $insertable->nonInsertableContent); + } + + public function testNotUpdatableIsFetched(): void + { + $updatable = new Updatable(); + $updatable->updatableContent = 'foo'; + $updatable->nonUpdatableContent = 'foo'; + + $this->_em->persist($updatable); + $this->_em->flush(); + + $updatable->updatableContent = 'bar'; + $updatable->nonUpdatableContent = 'baz'; + + $this->_em->flush(); + + self::assertEquals('foo', $updatable->nonUpdatableContent); + + $this->_em->clear(); + + $cleanUpdatable = $this->_em->find(Updatable::class, $updatable->id); + + self::assertEquals('bar', $cleanUpdatable->updatableContent); + self::assertEquals('foo', $cleanUpdatable->nonUpdatableContent); + } +} diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index e3b05196cbf..9b17ed30270 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -68,6 +68,8 @@ use Doctrine\Tests\Models\Enums\Suit; use Doctrine\Tests\Models\TypedProperties\Contact; use Doctrine\Tests\Models\TypedProperties\UserTyped; +use Doctrine\Tests\Models\Upsertable\Insertable; +use Doctrine\Tests\Models\Upsertable\Updatable; use Doctrine\Tests\OrmTestCase; use function assert; @@ -1145,6 +1147,30 @@ public function testReservedWordInTableColumn(): void self::assertSame('count', $metadata->getFieldMapping('count')['columnName']); } + public function testInsertableColumn(): void + { + $metadata = $this->createClassMetadata(Insertable::class); + + $mapping = $metadata->getFieldMapping('nonInsertableContent'); + + self::assertArrayHasKey('notInsertable', $mapping); + self::assertArrayHasKey('generated', $mapping); + self::assertSame(ClassMetadataInfo::GENERATED_INSERT, $mapping['generated']); + self::assertArrayNotHasKey('notInsertable', $metadata->getFieldMapping('insertableContent')); + } + + public function testUpdatableColumn(): void + { + $metadata = $this->createClassMetadata(Updatable::class); + + $mapping = $metadata->getFieldMapping('nonUpdatableContent'); + + self::assertArrayHasKey('notUpdatable', $mapping); + self::assertArrayHasKey('generated', $mapping); + self::assertSame(ClassMetadataInfo::GENERATED_ALWAYS, $mapping['generated']); + self::assertArrayNotHasKey('notUpdatable', $metadata->getFieldMapping('updatableContent')); + } + /** * @requires PHP 8.1 */ diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php index 5010b6c9349..65d3343f873 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataTest.php @@ -67,7 +67,10 @@ public function testClassMetadataInstanceSerialization(): void $cm->setDiscriminatorColumn(['name' => 'disc', 'type' => 'integer']); $cm->mapOneToOne(['fieldName' => 'phonenumbers', 'targetEntity' => 'CmsAddress', 'mappedBy' => 'foo']); $cm->markReadOnly(); + $cm->mapField(['fieldName' => 'status', 'notInsertable' => true, 'generated' => ClassMetadata::GENERATED_ALWAYS]); $cm->addNamedQuery(['name' => 'dql', 'query' => 'foo']); + + self::assertTrue($cm->requiresFetchAfterChange); self::assertEquals(1, count($cm->associationMappings)); $serialized = serialize($cm); @@ -92,6 +95,7 @@ public function testClassMetadataInstanceSerialization(): void self::assertEquals(CMS\CmsAddress::class, $oneOneMapping['targetEntity']); self::assertTrue($cm->isReadOnly); self::assertEquals(['dql' => ['name' => 'dql', 'query' => 'foo', 'dql' => 'foo']], $cm->namedQueries); + self::assertTrue($cm->requiresFetchAfterChange); } public function testFieldIsNullable(): void diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Insertable.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Insertable.php new file mode 100644 index 00000000000..403cdb2ef2e --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Insertable.php @@ -0,0 +1,29 @@ +setPrimaryTable( + ['name' => 'insertable_column'] +); + +$metadata->mapField( + [ + 'id' => true, + 'fieldName' => 'id', + ] +); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + +$metadata->mapField( + [ + 'fieldName' => 'nonInsertableContent', + 'notInsertable' => true, + 'options' => ['default' => '1234'], + 'generated' => ClassMetadataInfo::GENERATED_INSERT, + ] +); +$metadata->mapField( + ['fieldName' => 'insertableContent'] +); diff --git a/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Updatable.php b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Updatable.php new file mode 100644 index 00000000000..9fe2627c0e6 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/php/Doctrine.Tests.Models.Upsertable.Updatable.php @@ -0,0 +1,28 @@ +setPrimaryTable( + ['name' => 'updatable_column'] +); + +$metadata->mapField( + [ + 'id' => true, + 'fieldName' => 'id', + ] +); +$metadata->setIdGeneratorType(ClassMetadataInfo::GENERATOR_TYPE_AUTO); + +$metadata->mapField( + [ + 'fieldName' => 'nonUpdatableContent', + 'notUpdatable' => true, + 'generated' => ClassMetadataInfo::GENERATED_ALWAYS, + ] +); +$metadata->mapField( + ['fieldName' => 'updatableContent'] +); diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.xml new file mode 100644 index 00000000000..6a216375822 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.xml b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.xml new file mode 100644 index 00000000000..acaf07a8cd7 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/xml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.yml new file mode 100644 index 00000000000..4e5e8531841 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Insertable.dcm.yml @@ -0,0 +1,17 @@ +Doctrine\Tests\Models\Upsertable\Insertable: + type: entity + table: insertable_column + id: + id: + generator: + strategy: AUTO + fields: + nonInsertableContent: + type: string + insertable: false + generated: INSERT + options: + default: 1234 + insertableContent: + type: string + insertable: true \ No newline at end of file diff --git a/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.yml b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.yml new file mode 100644 index 00000000000..386ae77209b --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Mapping/yaml/Doctrine.Tests.Models.Upsertable.Updatable.dcm.yml @@ -0,0 +1,17 @@ +Doctrine\Tests\Models\Upsertable\Updatable: + type: entity + table: updatable_column + id: + id: + generator: + strategy: AUTO + fields: + nonUpdatableContent: + type: string + updatable: false + generated: ALWAYS + options: + default: 1234 + updatableContent: + type: string + updatable: true From 1e972b6e0e3468355901a301735d859165490af2 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 12 Jan 2022 10:06:40 +0100 Subject: [PATCH 4/5] Add errors caused by the lexer update to the baselines (#9360) --- phpstan-baseline.neon | 20 ++++++++++++++++++++ psalm-baseline.xml | 33 ++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1329633957b..000a029dbe7 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1335,6 +1335,11 @@ parameters: count: 1 path: lib/Doctrine/ORM/Query/AST/Functions/LowerFunction.php + - + message: "#^Property Doctrine\\\\ORM\\\\Query\\\\AST\\\\Functions\\\\TrimFunction\\:\\:\\$trimChar \\(bool\\) does not accept string\\.$#" + count: 1 + path: lib/Doctrine/ORM/Query/AST/Functions/TrimFunction.php + - message: "#^Parameter \\#1 \\$simpleArithmeticExpr of method Doctrine\\\\ORM\\\\Query\\\\SqlWalker\\:\\:walkSimpleArithmeticExpression\\(\\) expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#" count: 1 @@ -1420,6 +1425,16 @@ parameters: count: 1 path: lib/Doctrine/ORM/Query/Parser.php + - + message: "#^Method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:ArithmeticTerm\\(\\) should return Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticTerm but returns Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticFactor\\|string\\.$#" + count: 1 + path: lib/Doctrine/ORM/Query/Parser.php + + - + message: "#^Method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:SimpleArithmeticExpression\\(\\) should return Doctrine\\\\ORM\\\\Query\\\\AST\\\\SimpleArithmeticExpression but returns Doctrine\\\\ORM\\\\Query\\\\AST\\\\ArithmeticTerm\\|string\\.$#" + count: 1 + path: lib/Doctrine/ORM/Query/Parser.php + - message: """ #^PHPDoc tag @return has invalid value \\(AST\\\\BetweenExpression\\| @@ -1435,6 +1450,11 @@ parameters: count: 1 path: lib/Doctrine/ORM/Query/Parser.php + - + message: "#^Parameter \\#1 \\$tokenType of method Doctrine\\\\ORM\\\\Query\\\\Parser\\:\\:isAggregateFunction\\(\\) expects 1\\|2\\|3\\|4\\|5\\|6\\|7\\|8\\|9\\|10\\|11\\|12\\|13\\|14\\|15\\|16\\|17\\|18\\|19\\|100\\|101\\|102\\|200\\|201\\|202\\|203\\|204\\|205\\|206\\|207\\|208\\|209\\|210\\|211\\|212\\|213\\|214\\|215\\|216\\|217\\|218\\|219\\|220\\|221\\|222\\|223\\|224\\|225\\|226\\|227\\|228\\|229\\|230\\|231\\|232\\|233\\|234\\|235\\|236\\|237\\|238\\|239\\|240\\|241\\|242\\|243\\|244\\|245\\|246\\|247\\|248\\|249\\|250\\|251\\|252\\|253\\|254\\|255\\|256, int\\|string\\|null given\\.$#" + count: 2 + path: lib/Doctrine/ORM/Query/Parser.php + - message: "#^Parameter \\#2 \\$stringPattern of class Doctrine\\\\ORM\\\\Query\\\\AST\\\\LikeExpression constructor expects Doctrine\\\\ORM\\\\Query\\\\AST\\\\InputParameter, Doctrine\\\\ORM\\\\Query\\\\AST\\\\Node given\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 04a2d7559c3..75ee588df6f 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -2122,6 +2122,9 @@ $class->associationMappings + + $parser->getLexer()->token['value'] + $fieldMapping $pathExpression @@ -2202,6 +2205,9 @@ + + $lexer->token['value'] + $value @@ -2589,11 +2595,21 @@ call_user_func($functionClass, $functionName) call_user_func($functionClass, $functionName) - + + $lookaheadType + + SelectStatement|UpdateStatement|DeleteStatement + string + string + string + string + string - + + $factors[0] $primary + $terms[0] $this->CollectionMemberExpression() $this->ComparisonExpression() $this->EmptyCollectionComparisonExpression() @@ -2603,9 +2619,11 @@ $this->LikeExpression() $this->NullComparisonExpression() - + AST\BetweenExpression| ArithmeticFactor + ArithmeticTerm + SimpleArithmeticExpression $this->lexer->getLiteral($token) @@ -2643,7 +2661,7 @@ $this->ConditionalExpression() $this->ConditionalExpression() - + $aliasIdentVariable $dql $field @@ -2651,7 +2669,6 @@ $functionName $functionName $functionName - $lookaheadType $resultVariable $this->lexer->lookahead['value'] $this->lexer->lookahead['value'] @@ -2668,7 +2685,7 @@ $token['value'] $token['value'] - + $glimpse['type'] $glimpse['value'] $lookahead['type'] @@ -2739,12 +2756,14 @@ $token['type'] $token['type'] $token['type'] - $token['type'] $token['value'] $token['value'] $token['value'] $token['value'] + + $value + getNumberOfRequiredParameters From ee591195cf738132a9723ae18d2ca5dde59bf97f Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 12 Jan 2022 11:00:07 +0100 Subject: [PATCH 5/5] Use EntityManagerInterface in type declarations (#9325) --- UPGRADE.md | 7 ++ lib/Doctrine/ORM/EntityRepository.php | 4 +- lib/Doctrine/ORM/Event/LifecycleEventArgs.php | 4 +- .../ORM/Event/LoadClassMetadataEventArgs.php | 6 +- lib/Doctrine/ORM/Event/PostFlushEventArgs.php | 5 +- lib/Doctrine/ORM/Event/PreFlushEventArgs.php | 5 +- lib/Doctrine/ORM/Id/AbstractIdGenerator.php | 61 +++++++++++++++- lib/Doctrine/ORM/Id/AssignedGenerator.php | 6 +- .../ORM/Id/BigIntegerIdentityGenerator.php | 4 +- lib/Doctrine/ORM/Id/IdentityGenerator.php | 4 +- lib/Doctrine/ORM/Id/SequenceGenerator.php | 4 +- lib/Doctrine/ORM/Id/TableGenerator.php | 6 +- lib/Doctrine/ORM/Id/UuidGenerator.php | 4 +- .../Entity/BasicEntityPersister.php | 2 +- .../Entity/JoinedSubclassPersister.php | 2 +- lib/Doctrine/ORM/Query/FilterCollection.php | 3 +- lib/Doctrine/ORM/UnitOfWork.php | 2 +- phpstan-baseline.neon | 42 +++-------- psalm-baseline.xml | 32 ++------- psalm.xml | 1 + .../EventListener/CacheMetadataListener.php | 4 +- .../ORM/Cache/DefaultCacheFactoryTest.php | 4 +- .../ORM/Cache/DefaultEntityHydratorTest.php | 4 +- .../Tests/ORM/Cache/DefaultQueryCacheTest.php | 3 +- .../AbstractCollectionPersisterTest.php | 6 +- ...ReadWriteCachedCollectionPersisterTest.php | 4 +- .../ReadOnlyCachedCollectionPersisterTest.php | 4 +- ...ReadWriteCachedCollectionPersisterTest.php | 4 +- .../Entity/AbstractEntityPersisterTest.php | 6 +- ...rictReadWriteCachedEntityPersisterTest.php | 4 +- .../ReadOnlyCachedEntityPersisterTest.php | 4 +- .../ReadWriteCachedEntityPersisterTest.php | 4 +- .../Functional/ManyToOneOrphanRemovalTest.php | 4 +- .../Tests/ORM/Functional/MergeProxiesTest.php | 3 +- .../ORM/Functional/Ticket/DDC2415Test.php | 4 +- .../ORM/Functional/Ticket/GH5804Test.php | 4 +- .../ORM/Hydration/ResultSetMappingTest.php | 4 +- .../Tests/ORM/Id/AbstractIdGeneratorTest.php | 72 +++++++++++++++++++ .../Tests/ORM/Id/AssignedGeneratorTest.php | 7 +- .../Tests/ORM/Id/SequenceGeneratorTest.php | 6 +- .../ORM/Mapping/AbstractMappingDriverTest.php | 6 +- .../ORM/Mapping/ClassMetadataFactoryTest.php | 7 +- ...tyPersisterCompositeTypeParametersTest.php | 4 +- ...sicEntityPersisterCompositeTypeSqlTest.php | 4 +- .../BasicEntityPersisterTypeValueSqlTest.php | 4 +- .../JoinedSubclassPersisterTest.php | 4 +- .../Tests/ORM/Query/FilterCollectionTest.php | 4 +- tests/Doctrine/Tests/ORM/QueryBuilderTest.php | 4 +- .../AttachEntityListenersListenerTest.php | 4 +- .../Tools/ResolveTargetEntityListenerTest.php | 4 +- .../Tests/ORM/Tools/SchemaValidatorTest.php | 4 +- .../Doctrine/Tests/OrmFunctionalTestCase.php | 5 +- 52 files changed, 255 insertions(+), 158 deletions(-) create mode 100644 tests/Doctrine/Tests/ORM/Id/AbstractIdGeneratorTest.php diff --git a/UPGRADE.md b/UPGRADE.md index 1d7da3c95ed..22ceaf2f7da 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,12 @@ # Upgrade to 2.11 +## Rename `AbstractIdGenerator::generate()` to `generateId()` + +Implementations of `AbstractIdGenerator` have to override the method +`generateId()` without calling the parent implementation. Not doing so is +deprecated. Calling `generate()` on any `AbstractIdGenerator` implementation +is deprecated. + ## PSR-6-based second level cache The second level cache has been reworked to consume a PSR-6 cache. Using a diff --git a/lib/Doctrine/ORM/EntityRepository.php b/lib/Doctrine/ORM/EntityRepository.php index 3ae7f812b9c..20eb08e8ab0 100644 --- a/lib/Doctrine/ORM/EntityRepository.php +++ b/lib/Doctrine/ORM/EntityRepository.php @@ -39,7 +39,7 @@ class EntityRepository implements ObjectRepository, Selectable /** @var string */ protected $_entityName; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $_em; /** @var ClassMetadata */ @@ -282,7 +282,7 @@ public function getClassName() } /** - * @return EntityManager + * @return EntityManagerInterface */ protected function getEntityManager() { diff --git a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php index 21a6ccdb98f..24a0bf22d5f 100644 --- a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php +++ b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php @@ -4,7 +4,7 @@ namespace Doctrine\ORM\Event; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\Event\LifecycleEventArgs as BaseLifecycleEventArgs; /** @@ -28,7 +28,7 @@ public function getEntity() /** * Retrieves associated EntityManager. * - * @return EntityManager + * @return EntityManagerInterface */ public function getEntityManager() { diff --git a/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php b/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php index e7e81fa5b8c..815575cf2b7 100644 --- a/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php +++ b/lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php @@ -4,14 +4,14 @@ namespace Doctrine\ORM\Event; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\Event\LoadClassMetadataEventArgs as BaseLoadClassMetadataEventArgs; /** * Class that holds event arguments for a loadMetadata event. * - * @method __construct(ClassMetadata $classMetadata, EntityManager $objectManager) + * @method __construct(ClassMetadata $classMetadata, EntityManagerInterface $objectManager) * @method ClassMetadata getClassMetadata() */ class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs @@ -19,7 +19,7 @@ class LoadClassMetadataEventArgs extends BaseLoadClassMetadataEventArgs /** * Retrieve associated EntityManager. * - * @return EntityManager + * @return EntityManagerInterface */ public function getEntityManager() { diff --git a/lib/Doctrine/ORM/Event/PostFlushEventArgs.php b/lib/Doctrine/ORM/Event/PostFlushEventArgs.php index e7eae7d4464..1e7c06b6a7f 100644 --- a/lib/Doctrine/ORM/Event/PostFlushEventArgs.php +++ b/lib/Doctrine/ORM/Event/PostFlushEventArgs.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Event; use Doctrine\Common\EventArgs; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; /** @@ -15,7 +14,7 @@ */ class PostFlushEventArgs extends EventArgs { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; public function __construct(EntityManagerInterface $em) @@ -26,7 +25,7 @@ public function __construct(EntityManagerInterface $em) /** * Retrieves associated EntityManager. * - * @return EntityManager + * @return EntityManagerInterface */ public function getEntityManager() { diff --git a/lib/Doctrine/ORM/Event/PreFlushEventArgs.php b/lib/Doctrine/ORM/Event/PreFlushEventArgs.php index 3847afe44b5..c7d2fef4885 100644 --- a/lib/Doctrine/ORM/Event/PreFlushEventArgs.php +++ b/lib/Doctrine/ORM/Event/PreFlushEventArgs.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Event; use Doctrine\Common\EventArgs; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; /** @@ -15,7 +14,7 @@ */ class PreFlushEventArgs extends EventArgs { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; public function __construct(EntityManagerInterface $em) @@ -24,7 +23,7 @@ public function __construct(EntityManagerInterface $em) } /** - * @return EntityManager + * @return EntityManagerInterface */ public function getEntityManager() { diff --git a/lib/Doctrine/ORM/Id/AbstractIdGenerator.php b/lib/Doctrine/ORM/Id/AbstractIdGenerator.php index 397d5ea1123..5a42a3faf43 100644 --- a/lib/Doctrine/ORM/Id/AbstractIdGenerator.php +++ b/lib/Doctrine/ORM/Id/AbstractIdGenerator.php @@ -4,10 +4,54 @@ namespace Doctrine\ORM\Id; +use Doctrine\Deprecations\Deprecation; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; +use InvalidArgumentException; +use LogicException; + +use function get_debug_type; +use function sprintf; abstract class AbstractIdGenerator { + /** @var bool */ + private $alreadyDelegatedToGenerateId = false; + + /** + * Generates an identifier for an entity. + * + * @deprecated Call {@see generateId()} instead. + * + * @param object|null $entity + * + * @return mixed + */ + public function generate(EntityManager $em, $entity) + { + if ($this->alreadyDelegatedToGenerateId) { + throw new LogicException(sprintf( + 'Endless recursion detected in %s. Please implement generateId() without calling the parent implementation.', + get_debug_type($this) + )); + } + + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/pull/9325', + '%s::generate() is deprecated, call generateId() instead.', + get_debug_type($this) + ); + + $this->alreadyDelegatedToGenerateId = true; + + try { + return $this->generateId($em, $entity); + } finally { + $this->alreadyDelegatedToGenerateId = false; + } + } + /** * Generates an identifier for an entity. * @@ -15,7 +59,22 @@ abstract class AbstractIdGenerator * * @return mixed */ - abstract public function generate(EntityManager $em, $entity); + public function generateId(EntityManagerInterface $em, $entity) + { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/orm/pull/9325', + 'Not implementing %s in %s is deprecated.', + __FUNCTION__, + get_debug_type($this) + ); + + if (! $em instanceof EntityManager) { + throw new InvalidArgumentException('Unsupported entity manager implementation.'); + } + + return $this->generate($em, $entity); + } /** * Gets whether this generator is a post-insert generator which means that diff --git a/lib/Doctrine/ORM/Id/AssignedGenerator.php b/lib/Doctrine/ORM/Id/AssignedGenerator.php index 52a4c49f1a1..a06cf6031ca 100644 --- a/lib/Doctrine/ORM/Id/AssignedGenerator.php +++ b/lib/Doctrine/ORM/Id/AssignedGenerator.php @@ -4,7 +4,7 @@ namespace Doctrine\ORM\Id; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Exception\EntityMissingAssignedId; use function get_class; @@ -17,11 +17,11 @@ class AssignedGenerator extends AbstractIdGenerator /** * Returns the identifier assigned to the given entity. * - * {@inheritDoc} + * {@inheritdoc} * * @throws EntityMissingAssignedId */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { $class = $em->getClassMetadata(get_class($entity)); $idFields = $class->getIdentifierFieldNames(); diff --git a/lib/Doctrine/ORM/Id/BigIntegerIdentityGenerator.php b/lib/Doctrine/ORM/Id/BigIntegerIdentityGenerator.php index 4d8391335ce..16f6f2b7686 100644 --- a/lib/Doctrine/ORM/Id/BigIntegerIdentityGenerator.php +++ b/lib/Doctrine/ORM/Id/BigIntegerIdentityGenerator.php @@ -4,7 +4,7 @@ namespace Doctrine\ORM\Id; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; /** * Id generator that obtains IDs from special "identity" columns. These are columns @@ -33,7 +33,7 @@ public function __construct($sequenceName = null) /** * {@inheritDoc} */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { return (string) $em->getConnection()->lastInsertId($this->sequenceName); } diff --git a/lib/Doctrine/ORM/Id/IdentityGenerator.php b/lib/Doctrine/ORM/Id/IdentityGenerator.php index 84ba4eeeab2..1a003fc49ec 100644 --- a/lib/Doctrine/ORM/Id/IdentityGenerator.php +++ b/lib/Doctrine/ORM/Id/IdentityGenerator.php @@ -4,7 +4,7 @@ namespace Doctrine\ORM\Id; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; /** * Id generator that obtains IDs from special "identity" columns. These are columns @@ -33,7 +33,7 @@ public function __construct($sequenceName = null) /** * {@inheritDoc} */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { return (int) $em->getConnection()->lastInsertId($this->sequenceName); } diff --git a/lib/Doctrine/ORM/Id/SequenceGenerator.php b/lib/Doctrine/ORM/Id/SequenceGenerator.php index 9b194859d38..4d009835860 100644 --- a/lib/Doctrine/ORM/Id/SequenceGenerator.php +++ b/lib/Doctrine/ORM/Id/SequenceGenerator.php @@ -5,7 +5,7 @@ namespace Doctrine\ORM\Id; use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Serializable; use function serialize; @@ -51,7 +51,7 @@ public function __construct($sequenceName, $allocationSize) /** * {@inheritDoc} */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) { // Allocate new values diff --git a/lib/Doctrine/ORM/Id/TableGenerator.php b/lib/Doctrine/ORM/Id/TableGenerator.php index c65b5272617..2f8296d6cac 100644 --- a/lib/Doctrine/ORM/Id/TableGenerator.php +++ b/lib/Doctrine/ORM/Id/TableGenerator.php @@ -4,7 +4,7 @@ namespace Doctrine\ORM\Id; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; /** * Id generator that uses a single-row database table and a hi/lo algorithm. @@ -43,8 +43,8 @@ public function __construct($tableName, $sequenceName = 'default', $allocationSi /** * {@inheritDoc} */ - public function generate( - EntityManager $em, + public function generateId( + EntityManagerInterface $em, $entity ) { if ($this->_maxValue === null || $this->_nextValue === $this->_maxValue) { diff --git a/lib/Doctrine/ORM/Id/UuidGenerator.php b/lib/Doctrine/ORM/Id/UuidGenerator.php index e701c52fbbe..81dd9c85f76 100644 --- a/lib/Doctrine/ORM/Id/UuidGenerator.php +++ b/lib/Doctrine/ORM/Id/UuidGenerator.php @@ -7,7 +7,7 @@ use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\Deprecations\Deprecation; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Exception\NotSupported; use function method_exists; @@ -38,7 +38,7 @@ public function __construct() * * @throws NotSupported */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { $connection = $em->getConnection(); $sql = 'SELECT ' . $connection->getDatabasePlatform()->getGuidExpression(); diff --git a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php index d9ac746adc1..5e78bf083fa 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php @@ -276,7 +276,7 @@ public function executeInserts() $stmt->executeStatement(); if ($isPostInsertId) { - $generatedId = $idGenerator->generate($this->em, $entity); + $generatedId = $idGenerator->generateId($this->em, $entity); $id = [$this->class->identifier[0] => $generatedId]; $postInsertIds[] = [ 'generatedId' => $generatedId, diff --git a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php index aa195d04aa9..cba558216dc 100644 --- a/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php +++ b/lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php @@ -159,7 +159,7 @@ public function executeInserts() $rootTableStmt->executeStatement(); if ($isPostInsertId) { - $generatedId = $idGenerator->generate($this->em, $entity); + $generatedId = $idGenerator->generateId($this->em, $entity); $id = [$this->class->identifier[0] => $generatedId]; $postInsertIds[] = [ 'generatedId' => $generatedId, diff --git a/lib/Doctrine/ORM/Query/FilterCollection.php b/lib/Doctrine/ORM/Query/FilterCollection.php index cedbd8a8d5e..7e9ac71bab9 100644 --- a/lib/Doctrine/ORM/Query/FilterCollection.php +++ b/lib/Doctrine/ORM/Query/FilterCollection.php @@ -5,7 +5,6 @@ namespace Doctrine\ORM\Query; use Doctrine\ORM\Configuration; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\Filter\SQLFilter; use InvalidArgumentException; @@ -40,7 +39,7 @@ class FilterCollection /** * The EntityManager that "owns" this FilterCollection instance. * - * @var EntityManager + * @var EntityManagerInterface */ private $em; diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 2b45568d56c..cd5d727167a 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -986,7 +986,7 @@ private function persistNew(ClassMetadata $class, $entity): void $idGen = $class->idGenerator; if (! $idGen->isPostInsertGenerator()) { - $idValue = $idGen->generate($this->em, $entity); + $idValue = $idGen->generateId($this->em, $entity); if (! $idGen instanceof AssignedGenerator) { $idValue = [$class->getSingleIdentifierFieldName() => $this->convertSingleFieldIdentifierToPHPValue($class, $idValue)]; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6ec64518636..43d202f7ee0 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -176,34 +176,29 @@ parameters: path: lib/Doctrine/ORM/EntityManagerInterface.php - - message: "#^Method Doctrine\\\\ORM\\\\EntityRepository\\:\\:findOneBy\\(\\) should return T\\|null but returns object\\|null\\.$#" + message: "#^Method Doctrine\\\\ORM\\\\EntityRepository\\:\\:find\\(\\) should return T\\|null but returns object\\|null\\.$#" count: 1 path: lib/Doctrine/ORM/EntityRepository.php - - message: "#^Property Doctrine\\\\ORM\\\\EntityRepository\\\\:\\:\\$_em \\(Doctrine\\\\ORM\\\\EntityManager\\) does not accept Doctrine\\\\ORM\\\\EntityManagerInterface\\.$#" + message: "#^Method Doctrine\\\\ORM\\\\EntityRepository\\:\\:findOneBy\\(\\) should return T\\|null but returns object\\|null\\.$#" count: 1 path: lib/Doctrine/ORM/EntityRepository.php - - message: "#^Method Doctrine\\\\ORM\\\\Event\\\\LifecycleEventArgs\\:\\:getEntityManager\\(\\) should return Doctrine\\\\ORM\\\\EntityManager but returns Doctrine\\\\Persistence\\\\ObjectManager\\.$#" - count: 1 - path: lib/Doctrine/ORM/Event/LifecycleEventArgs.php - - - - message: "#^Method Doctrine\\\\ORM\\\\Event\\\\LoadClassMetadataEventArgs\\:\\:getEntityManager\\(\\) should return Doctrine\\\\ORM\\\\EntityManager but returns Doctrine\\\\Persistence\\\\ObjectManager\\.$#" + message: "#^Method Doctrine\\\\Persistence\\\\ObjectManager\\:\\:find\\(\\) invoked with 4 parameters, 2 required\\.$#" count: 1 - path: lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php + path: lib/Doctrine/ORM/EntityRepository.php - - message: "#^Property Doctrine\\\\ORM\\\\Event\\\\PostFlushEventArgs\\:\\:\\$em \\(Doctrine\\\\ORM\\\\EntityManager\\) does not accept Doctrine\\\\ORM\\\\EntityManagerInterface\\.$#" + message: "#^Method Doctrine\\\\ORM\\\\Event\\\\LifecycleEventArgs\\:\\:getEntityManager\\(\\) should return Doctrine\\\\ORM\\\\EntityManagerInterface but returns Doctrine\\\\Persistence\\\\ObjectManager\\.$#" count: 1 - path: lib/Doctrine/ORM/Event/PostFlushEventArgs.php + path: lib/Doctrine/ORM/Event/LifecycleEventArgs.php - - message: "#^Property Doctrine\\\\ORM\\\\Event\\\\PreFlushEventArgs\\:\\:\\$em \\(Doctrine\\\\ORM\\\\EntityManager\\) does not accept Doctrine\\\\ORM\\\\EntityManagerInterface\\.$#" + message: "#^Method Doctrine\\\\ORM\\\\Event\\\\LoadClassMetadataEventArgs\\:\\:getEntityManager\\(\\) should return Doctrine\\\\ORM\\\\EntityManagerInterface but returns Doctrine\\\\Persistence\\\\ObjectManager\\.$#" count: 1 - path: lib/Doctrine/ORM/Event/PreFlushEventArgs.php + path: lib/Doctrine/ORM/Event/LoadClassMetadataEventArgs.php - message: "#^Call to an undefined method Doctrine\\\\DBAL\\\\Platforms\\\\AbstractPlatform\\:\\:getTableHiLoCurrentValSql\\(\\)\\.$#" @@ -735,11 +730,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php - - - message: "#^Parameter \\#1 \\$em of method Doctrine\\\\ORM\\\\Id\\\\AbstractIdGenerator\\:\\:generate\\(\\) expects Doctrine\\\\ORM\\\\EntityManager, Doctrine\\\\ORM\\\\EntityManagerInterface given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php - - message: "#^Parameter \\#3 \\$hints of method Doctrine\\\\ORM\\\\Internal\\\\Hydration\\\\AbstractHydrator\\:\\:hydrateAll\\(\\) expects array\\, array\\ given\\.$#" count: 1 @@ -760,11 +750,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Persisters/Entity/CachedPersisterContext.php - - - message: "#^Parameter \\#1 \\$em of method Doctrine\\\\ORM\\\\Id\\\\AbstractIdGenerator\\:\\:generate\\(\\) expects Doctrine\\\\ORM\\\\EntityManager, Doctrine\\\\ORM\\\\EntityManagerInterface given\\.$#" - count: 1 - path: lib/Doctrine/ORM/Persisters/Entity/JoinedSubclassPersister.php - - message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$isEmbeddedClass\\.$#" count: 1 @@ -945,11 +930,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/Query/Expr/Select.php - - - message: "#^Property Doctrine\\\\ORM\\\\Query\\\\FilterCollection\\:\\:\\$em \\(Doctrine\\\\ORM\\\\EntityManager\\) does not accept Doctrine\\\\ORM\\\\EntityManagerInterface\\.$#" - count: 1 - path: lib/Doctrine/ORM/Query/FilterCollection.php - - message: "#^Property Doctrine\\\\ORM\\\\Query\\\\FilterCollection\\:\\:\\$filterHash is never written, only read\\.$#" count: 1 @@ -1865,11 +1845,6 @@ parameters: count: 1 path: lib/Doctrine/ORM/UnitOfWork.php - - - message: "#^Parameter \\#1 \\$em of method Doctrine\\\\ORM\\\\Id\\\\AbstractIdGenerator\\:\\:generate\\(\\) expects Doctrine\\\\ORM\\\\EntityManager, Doctrine\\\\ORM\\\\EntityManagerInterface given\\.$#" - count: 1 - path: lib/Doctrine/ORM/UnitOfWork.php - - message: "#^Parameter \\#3 \\$changeSet of class Doctrine\\\\ORM\\\\Event\\\\PreUpdateEventArgs constructor is passed by reference, so it expects variables only$#" count: 1 @@ -1889,4 +1864,3 @@ parameters: message: "#^Access to an undefined property Doctrine\\\\Persistence\\\\Mapping\\\\ClassMetadata\\:\\:\\$subClasses\\.$#" count: 1 path: lib/Doctrine/ORM/Utility/HierarchyDiscriminatorResolver.php - diff --git a/psalm-baseline.xml b/psalm-baseline.xml index be00684ee3b..38f15718f88 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -473,16 +473,16 @@ string - - $em - + + find + $this->getObjectManager() - EntityManager + EntityManagerInterface @@ -490,7 +490,7 @@ $this->getObjectManager() - EntityManager + EntityManagerInterface @@ -498,16 +498,6 @@ (string) $className - - - $em - - - - - $em - - BaseORMException @@ -1514,9 +1504,6 @@ - - $this->em - $value === null @@ -1593,9 +1580,6 @@ - - $this->em - $postInsertIds @@ -2314,8 +2298,7 @@ $filterHash - - $em + $this->enabledFilters @@ -3417,13 +3400,12 @@ - + $class $class $collectionToDelete $collectionToUpdate $commitOrder[$i] - $this->em ! is_object($object) diff --git a/psalm.xml b/psalm.xml index e36df95e5be..b83e3f2a23d 100644 --- a/psalm.xml +++ b/psalm.xml @@ -46,6 +46,7 @@ + diff --git a/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php b/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php index 5d441603069..612a90a9c3a 100644 --- a/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php +++ b/tests/Doctrine/Tests/EventListener/CacheMetadataListener.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\EventListener; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\Persistence\Event\LoadClassMetadataEventArgs; @@ -46,7 +46,7 @@ private function recordVisit(ClassMetadata $metadata): void $this->enabledItems[$metadata->getName()] = true; } - protected function enableCaching(ClassMetadata $metadata, EntityManager $em): void + protected function enableCaching(ClassMetadata $metadata, EntityManagerInterface $em): void { if ($this->isVisited($metadata)) { return; // Already handled in the past diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php index 9ccd8a1d45e..9b4db8c92df 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultCacheFactoryTest.php @@ -16,7 +16,7 @@ use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister; use Doctrine\ORM\Cache\Region\DefaultRegion; use Doctrine\ORM\Cache\RegionsConfiguration; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Persisters\Collection\OneToManyPersister; use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; @@ -39,7 +39,7 @@ class DefaultCacheFactoryTest extends OrmTestCase /** @var CacheFactory&MockObject */ private $factory; - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; /** @var RegionsConfiguration */ diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultEntityHydratorTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultEntityHydratorTest.php index bd5eaeac4dd..702874eab7e 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultEntityHydratorTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultEntityHydratorTest.php @@ -10,7 +10,7 @@ use Doctrine\ORM\Cache\EntityCacheEntry; use Doctrine\ORM\Cache\EntityCacheKey; use Doctrine\ORM\Cache\EntityHydrator; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\UnitOfWork; use Doctrine\Tests\Models\Cache\Country; use Doctrine\Tests\Models\Cache\State; @@ -24,7 +24,7 @@ class DefaultEntityHydratorTest extends OrmTestCase /** @var EntityHydrator */ private $structure; - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php index 17be99bd187..cae81dc113c 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php @@ -13,7 +13,6 @@ use Doctrine\ORM\Cache\QueryCache; use Doctrine\ORM\Cache\QueryCacheEntry; use Doctrine\ORM\Cache\QueryCacheKey; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\ResultSetMappingBuilder; use Doctrine\Tests\Mocks\CacheEntryMock; @@ -38,7 +37,7 @@ class DefaultQueryCacheTest extends OrmTestCase /** @var DefaultQueryCache */ private $queryCache; - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; /** @var CacheRegionMock */ diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php index fc98917b28e..8b12ff48b20 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/AbstractCollectionPersisterTest.php @@ -9,7 +9,7 @@ use Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister; use Doctrine\ORM\Cache\Persister\Collection\CachedCollectionPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Persisters\Collection\CollectionPersister; use Doctrine\Tests\Models\Cache\State; @@ -27,7 +27,7 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase /** @var CollectionPersister */ protected $collectionPersister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $em; /** @var array */ @@ -56,7 +56,7 @@ abstract class AbstractCollectionPersisterTest extends OrmTestCase 'loadCriteria', ]; - abstract protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister; + abstract protected function createPersister(EntityManagerInterface $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister; protected function setUp(): void { diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersisterTest.php index a36a4a8b9bc..6e014627533 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/NonStrictReadWriteCachedCollectionPersisterTest.php @@ -7,7 +7,7 @@ use Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister; use Doctrine\ORM\Cache\Persister\Collection\NonStrictReadWriteCachedCollectionPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Collection\CollectionPersister; /** @@ -18,7 +18,7 @@ class NonStrictReadWriteCachedCollectionPersisterTest extends AbstractCollection /** * {@inheritdoc} */ - protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister + protected function createPersister(EntityManagerInterface $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister { return new NonStrictReadWriteCachedCollectionPersister($persister, $region, $em, $mapping); } diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadOnlyCachedCollectionPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadOnlyCachedCollectionPersisterTest.php index e074409bb2e..9dbbb2a5f76 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadOnlyCachedCollectionPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadOnlyCachedCollectionPersisterTest.php @@ -7,7 +7,7 @@ use Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister; use Doctrine\ORM\Cache\Persister\Collection\ReadOnlyCachedCollectionPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Collection\CollectionPersister; /** @@ -15,7 +15,7 @@ */ class ReadOnlyCachedCollectionPersisterTest extends AbstractCollectionPersisterTest { - protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister + protected function createPersister(EntityManagerInterface $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister { return new ReadOnlyCachedCollectionPersister($persister, $region, $em, $mapping); } diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadWriteCachedCollectionPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadWriteCachedCollectionPersisterTest.php index 60a95fa0297..b7a0c662696 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadWriteCachedCollectionPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Collection/ReadWriteCachedCollectionPersisterTest.php @@ -10,7 +10,7 @@ use Doctrine\ORM\Cache\Persister\Collection\AbstractCollectionPersister; use Doctrine\ORM\Cache\Persister\Collection\ReadWriteCachedCollectionPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Collection\CollectionPersister; use Doctrine\Tests\Models\Cache\State; use ReflectionProperty; @@ -33,7 +33,7 @@ class ReadWriteCachedCollectionPersisterTest extends AbstractCollectionPersister 'unlock', ]; - protected function createPersister(EntityManager $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister + protected function createPersister(EntityManagerInterface $em, CollectionPersister $persister, Region $region, array $mapping): AbstractCollectionPersister { return new ReadWriteCachedCollectionPersister($persister, $region, $em, $mapping); } diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php index 7cccc87e866..f9bf93c1457 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/AbstractEntityPersisterTest.php @@ -10,7 +10,7 @@ use Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\CachedEntityPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\Persisters\Entity\EntityPersister; @@ -30,10 +30,10 @@ abstract class AbstractEntityPersisterTest extends OrmTestCase /** @var EntityPersister&MockObject */ protected $entityPersister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $em; - abstract protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister; + abstract protected function createPersister(EntityManagerInterface $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister; protected function setUp(): void { diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersisterTest.php index 24ae0390abe..46f6a9b4fdc 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/NonStrictReadWriteCachedEntityPersisterTest.php @@ -9,7 +9,7 @@ use Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\NonStrictReadWriteCachedEntityPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Persisters\Entity\EntityPersister; use Doctrine\Tests\Models\Cache\Country; @@ -20,7 +20,7 @@ */ class NonStrictReadWriteCachedEntityPersisterTest extends AbstractEntityPersisterTest { - protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister + protected function createPersister(EntityManagerInterface $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister { return new NonStrictReadWriteCachedEntityPersister($persister, $region, $em, $metadata); } diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadOnlyCachedEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadOnlyCachedEntityPersisterTest.php index aab93323545..e8214f18afd 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadOnlyCachedEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadOnlyCachedEntityPersisterTest.php @@ -8,7 +8,7 @@ use Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\ReadOnlyCachedEntityPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Persisters\Entity\EntityPersister; use Doctrine\Tests\Models\Cache\Country; @@ -18,7 +18,7 @@ */ class ReadOnlyCachedEntityPersisterTest extends AbstractEntityPersisterTest { - protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister + protected function createPersister(EntityManagerInterface $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister { return new ReadOnlyCachedEntityPersister($persister, $region, $em, $metadata); } diff --git a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersisterTest.php b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersisterTest.php index 34c0f273665..9a25b959002 100644 --- a/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/Persister/Entity/ReadWriteCachedEntityPersisterTest.php @@ -10,7 +10,7 @@ use Doctrine\ORM\Cache\Persister\Entity\AbstractEntityPersister; use Doctrine\ORM\Cache\Persister\Entity\ReadWriteCachedEntityPersister; use Doctrine\ORM\Cache\Region; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Persisters\Entity\EntityPersister; use Doctrine\Tests\Models\Cache\Country; @@ -21,7 +21,7 @@ */ class ReadWriteCachedEntityPersisterTest extends AbstractEntityPersisterTest { - protected function createPersister(EntityManager $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister + protected function createPersister(EntityManagerInterface $em, EntityPersister $persister, Region $region, ClassMetadata $metadata): AbstractEntityPersister { return new ReadWriteCachedEntityPersister($persister, $region, $em, $metadata); } diff --git a/tests/Doctrine/Tests/ORM/Functional/ManyToOneOrphanRemovalTest.php b/tests/Doctrine/Tests/ORM/Functional/ManyToOneOrphanRemovalTest.php index 6f4f0fdb0e7..55985aa74eb 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ManyToOneOrphanRemovalTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ManyToOneOrphanRemovalTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Functional; use Doctrine\DBAL\Connection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\Driver\XmlDriver; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Tests\Models\OrnementalOrphanRemoval\Person; @@ -87,7 +87,7 @@ public function testOrphanRemovalIsPurelyOrnemental(): void protected function getEntityManager( ?Connection $connection = null, ?MappingDriver $mappingDriver = null - ): EntityManager { + ): EntityManagerInterface { return parent::getEntityManager($connection, new XmlDriver( __DIR__ . DIRECTORY_SEPARATOR . 'xml' )); diff --git a/tests/Doctrine/Tests/ORM/Functional/MergeProxiesTest.php b/tests/Doctrine/Tests/ORM/Functional/MergeProxiesTest.php index 6677def1a3c..31185b518b6 100644 --- a/tests/Doctrine/Tests/ORM/Functional/MergeProxiesTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/MergeProxiesTest.php @@ -10,6 +10,7 @@ use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Proxy\Proxy; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Tests\Models\Generic\DateTimeModel; @@ -233,7 +234,7 @@ public function testMergingUnInitializedProxyDoesNotInitializeIt(): void ); } - private function createEntityManager(SQLLogger $logger): EntityManager + private function createEntityManager(SQLLogger $logger): EntityManagerInterface { $config = new Configuration(); diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2415Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2415Test.php index 0c74c1fe92c..e68dd582170 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2415Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2415Test.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Functional\Ticket; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Id\AbstractIdGenerator; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\Driver\StaticPHPDriver; @@ -108,7 +108,7 @@ public static function loadMetadata(ClassMetadataInfo $metadata): void class DDC2415Generator extends AbstractIdGenerator { - public function generate(EntityManager $em, $entity): string + public function generateId(EntityManagerInterface $em, $entity): string { return md5($entity->getName()); } diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5804Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5804Test.php index 8bad22705dd..3b4b1df8d9a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5804Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5804Test.php @@ -6,7 +6,7 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Id\AbstractIdGenerator; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\CustomIdGenerator; @@ -54,7 +54,7 @@ final class GH5804Generator extends AbstractIdGenerator /** * {@inheritdoc} */ - public function generate(EntityManager $em, $entity) + public function generateId(EntityManagerInterface $em, $entity) { return 'test5804'; } diff --git a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php index 7ac96c37efd..fef4eb0793d 100644 --- a/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php +++ b/tests/Doctrine/Tests/ORM/Hydration/ResultSetMappingTest.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Hydration; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\ORM\Query\ResultSetMappingBuilder; @@ -24,7 +24,7 @@ class ResultSetMappingTest extends OrmTestCase /** @var ResultSetMapping */ private $_rsm; - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $entityManager; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Id/AbstractIdGeneratorTest.php b/tests/Doctrine/Tests/ORM/Id/AbstractIdGeneratorTest.php new file mode 100644 index 00000000000..974a6047b63 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Id/AbstractIdGeneratorTest.php @@ -0,0 +1,72 @@ +receivedEm = $em; + $this->receivedEntity = $entity; + + return '4711'; + } + }; + + $em = $this->createMock(EntityManager::class); + $entity = new stdClass(); + + $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/9325'); + + self::assertSame('4711', $generator->generateId($em, $entity)); + self::assertSame($em, $generator->receivedEm); + self::assertSame($entity, $generator->receivedEntity); + } + + public function testNoEndlessRecursionOnGenerateId(): void + { + $generator = new class extends AbstractIdGenerator + { + }; + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Endless recursion detected in Doctrine\ORM\Id\AbstractIdGenerator@anonymous. Please implement generateId() without calling the parent implementation.'); + + $generator->generateId($this->createMock(EntityManager::class), (object) []); + } + + public function testNoEndlessRecursionOnGenerate(): void + { + $generator = new class extends AbstractIdGenerator + { + }; + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Endless recursion detected in Doctrine\ORM\Id\AbstractIdGenerator@anonymous. Please implement generateId() without calling the parent implementation.'); + + $generator->generate($this->createMock(EntityManager::class), (object) []); + } +} diff --git a/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php b/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php index 54ec5668116..c446fbef2f6 100644 --- a/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Id/AssignedGeneratorTest.php @@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Id; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Id\AssignedGenerator; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; @@ -35,7 +36,7 @@ public function testThrowsExceptionIfIdNotAssigned($entity): void { $this->expectException(ORMException::class); - $this->assignedGen->generate($this->entityManager, $entity); + $this->assignedGen->generateId($this->entityManager, $entity); } public function entitiesWithoutId(): array @@ -50,13 +51,13 @@ public function testCorrectIdGeneration(): void { $entity = new AssignedSingleIdEntity(); $entity->myId = 1; - $id = $this->assignedGen->generate($this->entityManager, $entity); + $id = $this->assignedGen->generateId($this->entityManager, $entity); self::assertEquals(['myId' => 1], $id); $entity = new AssignedCompositeIdEntity(); $entity->myId2 = 2; $entity->myId1 = 4; - $id = $this->assignedGen->generate($this->entityManager, $entity); + $id = $this->assignedGen->generateId($this->entityManager, $entity); self::assertEquals(['myId1' => 4, 'myId2' => 2], $id); } } diff --git a/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php b/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php index 02af3a790db..0a71527f826 100644 --- a/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php +++ b/tests/Doctrine/Tests/ORM/Id/SequenceGeneratorTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Id; use BadMethodCallException; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Id\SequenceGenerator; use Doctrine\Tests\Mocks\ArrayResultFactory; use Doctrine\Tests\Mocks\ConnectionMock; @@ -13,7 +13,7 @@ class SequenceGeneratorTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $entityManager; /** @var SequenceGenerator */ @@ -45,7 +45,7 @@ public function testGeneration(): void $this->connection->setQueryResult(ArrayResultFactory::createFromArray([[(int) ($i / 10) * 10]])); } - $id = $this->sequenceGenerator->generate($this->entityManager, null); + $id = $this->sequenceGenerator->generateId($this->entityManager, null); self::assertSame($i, $id); self::assertSame((int) ($i / 10) * 10 + 10, $this->sequenceGenerator->getCurrentMaxValue()); diff --git a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php index 9b17ed30270..ff28accdb6b 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/AbstractMappingDriverTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Mapping; use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping\ClassMetadata; @@ -100,10 +100,10 @@ public function createClassMetadata(string $entityClassName): ClassMetadata return $class; } - protected function createClassMetadataFactory(?EntityManager $em = null): ClassMetadataFactory + protected function createClassMetadataFactory(?EntityManagerInterface $em = null): ClassMetadataFactory { $driver = $this->loadDriver(); - $em = $em ?: $this->getTestEntityManager(); + $em = $em ?? $this->getTestEntityManager(); $factory = new ClassMetadataFactory(); $em->getConfiguration()->setMetadataDriverImpl($driver); $factory->setEntityManager($em); diff --git a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php index f41e75ba40c..a1517f78f9d 100644 --- a/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/ORM/Mapping/ClassMetadataFactoryTest.php @@ -7,7 +7,6 @@ use Doctrine\Common\EventManager; use Doctrine\DBAL\Connection; use Doctrine\ORM\Configuration; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Event\OnClassMetadataNotFoundEventArgs; use Doctrine\ORM\Events; @@ -589,7 +588,11 @@ class TestEntity1 class CustomIdGenerator extends AbstractIdGenerator { - public function generate(EntityManager $em, $entity): void + /** + * {@inheritdoc} + */ + public function generateId(EntityManagerInterface $em, $entity): string { + return 'foo'; } } diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeParametersTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeParametersTest.php index 805d7483913..fe6bf4b33b6 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeParametersTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeParametersTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Persisters; use Doctrine\Common\Collections\Criteria; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; use Doctrine\Tests\Models\GeoNames\Admin1; use Doctrine\Tests\Models\GeoNames\Admin1AlternateName; @@ -17,7 +17,7 @@ class BasicEntityPersisterCompositeTypeParametersTest extends OrmTestCase /** @var BasicEntityPersister */ protected $persister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $entityManager; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeSqlTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeSqlTest.php index 75dbb9b3486..da49050aa02 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeSqlTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterCompositeTypeSqlTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Persisters; use Doctrine\Common\Collections\Expr\Comparison; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; use Doctrine\ORM\Persisters\Exception\CantUseInOperatorOnCompositeKeys; use Doctrine\Tests\Models\GeoNames\Admin1AlternateName; @@ -16,7 +16,7 @@ class BasicEntityPersisterCompositeTypeSqlTest extends OrmTestCase /** @var BasicEntityPersister */ protected $persister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $entityManager; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php index 647ed645172..c0045a593e6 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php @@ -7,7 +7,7 @@ use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Expr\Comparison; use Doctrine\DBAL\Types\Type as DBALType; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Entity\BasicEntityPersister; use Doctrine\Tests\Models\CustomType\CustomTypeChild; use Doctrine\Tests\Models\CustomType\CustomTypeParent; @@ -22,7 +22,7 @@ class BasicEntityPersisterTypeValueSqlTest extends OrmTestCase /** @var BasicEntityPersister */ protected $persister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $entityManager; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Persisters/JoinedSubclassPersisterTest.php b/tests/Doctrine/Tests/ORM/Persisters/JoinedSubclassPersisterTest.php index 31411d306bf..e9902849bc6 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/JoinedSubclassPersisterTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/JoinedSubclassPersisterTest.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Persisters; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Persisters\Entity\JoinedSubclassPersister; use Doctrine\Tests\Models\JoinedInheritanceType\RootClass; use Doctrine\Tests\OrmTestCase; @@ -19,7 +19,7 @@ class JoinedSubClassPersisterTest extends OrmTestCase /** @var JoinedSubclassPersister */ protected $persister; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $em; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Query/FilterCollectionTest.php b/tests/Doctrine/Tests/ORM/Query/FilterCollectionTest.php index f8ff65f433f..304c31d169d 100644 --- a/tests/Doctrine/Tests/ORM/Query/FilterCollectionTest.php +++ b/tests/Doctrine/Tests/ORM/Query/FilterCollectionTest.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Query; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Query\Filter\SQLFilter; use Doctrine\Tests\OrmTestCase; @@ -14,7 +14,7 @@ */ class FilterCollectionTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php index fbdf1252a28..26d1db475d2 100644 --- a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php @@ -7,7 +7,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\Cache; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Parameter; @@ -29,7 +29,7 @@ */ class QueryBuilderTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $entityManager; protected function setUp(): void diff --git a/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php b/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php index b5430ef7a67..6761f1a219e 100644 --- a/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/AttachEntityListenersListenerTest.php @@ -4,7 +4,7 @@ namespace Doctrine\Tests\ORM\Tools; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Column; @@ -19,7 +19,7 @@ class AttachEntityListenersListenerTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; /** @var AttachEntityListenersListener */ diff --git a/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php b/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php index 80d0957761d..64f0438ecf3 100644 --- a/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/ResolveTargetEntityListenerTest.php @@ -5,7 +5,7 @@ namespace Doctrine\Tests\ORM\Tools; use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping\ClassMetadataFactory; use Doctrine\ORM\Mapping\Column; @@ -22,7 +22,7 @@ class ResolveTargetEntityListenerTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em; /** @var ResolveTargetEntityListener */ diff --git a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php index 97aa29f3fc5..501fae65ecc 100644 --- a/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php +++ b/tests/Doctrine/Tests/ORM/Tools/SchemaValidatorTest.php @@ -6,7 +6,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\DiscriminatorMap; use Doctrine\ORM\Mapping\Embeddable; @@ -29,7 +29,7 @@ class SchemaValidatorTest extends OrmTestCase { - /** @var EntityManager */ + /** @var EntityManagerInterface */ private $em = null; /** @var SchemaValidator */ diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 7fabb882a24..fbaa297eb65 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -17,6 +17,7 @@ use Doctrine\ORM\Cache\Logging\StatisticsCacheLogger; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Exception\ORMException; use Doctrine\ORM\Tools\DebugUnitOfWorkListener; use Doctrine\ORM\Tools\SchemaTool; @@ -75,7 +76,7 @@ abstract class OrmFunctionalTestCase extends OrmTestCase */ protected static $sharedConn; - /** @var EntityManager */ + /** @var EntityManagerInterface */ protected $_em; /** @var SchemaTool */ @@ -706,7 +707,7 @@ protected function setUp(): void protected function getEntityManager( ?Connection $connection = null, ?MappingDriver $mappingDriver = null - ): EntityManager { + ): EntityManagerInterface { // NOTE: Functional tests use their own shared metadata cache, because // the actual database platform used during execution has effect on some // metadata mapping behaviors (like the choice of the ID generation).