diff --git a/composer.json b/composer.json index ccdaeae..a28bbd8 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "doctrine/annotations": "^2.0.1", "doctrine/data-fixtures": "^1.6", "doctrine/orm": "^2.14 || ^3.0", - "phpstan/phpstan": "^1.10.58", + "phpstan/phpstan": "^2.2", "symfony/cache": "^5.4.35 || ^6.4.3 || ^7.0", "symfony/doctrine-bridge": "^5.4.35 || ^6.4.3 || ^7.0", "symfony/uid": "^5.4.35 || ^6.4.3 || ^7.0" diff --git a/phpstan.neon b/phpstan.neon index f0dad3e..8e5cec5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -9,6 +9,7 @@ parameters: - tests/data/doctrine_fixtures/TestFixture2.php - tests/_support/UnitTester.php reportUnmatchedIgnoredErrors: true + treatPhpDocTypesAsCertain: false ignoreErrors: - path: tests/ message: '#Property \S+ is never read, only written#' @@ -20,4 +21,6 @@ parameters: message: '#Method \S+ has no return type specified#' - path: tests/ message: '#(?:Method|Property) .+ with generic (?:interface|class) \S+ does not specify its types#' + - path: tests/ + identifier: property.unusedType - identifier: missingType.iterableValue diff --git a/src/Codeception/Module/Doctrine.php b/src/Codeception/Module/Doctrine.php index 9d5a013..4e879d1 100644 --- a/src/Codeception/Module/Doctrine.php +++ b/src/Codeception/Module/Doctrine.php @@ -254,15 +254,8 @@ protected function retrieveEntityManager(): void } - if (!($this->em instanceof EntityManagerInterface)) { - throw new ModuleConfigException( - __CLASS__, - "Connection object is not an instance of \\Doctrine\\ORM\\EntityManagerInterface.\n" - . "Use `connection_callback` or dependent framework modules to specify one" - ); - } - $connection = $this->em->getConnection(); + // @phpstan-ignore-next-line if (method_exists($connection, 'getNativeConnection')) { $connection->getNativeConnection(); } else { @@ -732,7 +725,7 @@ public function loadFixtures($fixtures, bool $append = true): void try { $fixtureInstance = new $fixture(); - } catch (Exception $exception) { // @phpstan-ignore-line https://github.com/phpstan/phpstan/issues/6574 + } catch (Exception $exception) { throw new ModuleException( __CLASS__, sprintf( @@ -991,6 +984,7 @@ protected function _buildAssociationQuery(QueryBuilder $qb, string $assoc, strin { $data = $this->em->getClassMetadata($assoc); foreach ($params as $key => $val) { + // @phpstan-ignore-next-line if ($data->associationMappings !== null && array_key_exists($key, $data->associationMappings)) { $map = $data->associationMappings[$key]; if (is_array($val)) { @@ -1005,7 +999,9 @@ protected function _buildAssociationQuery(QueryBuilder $qb, string $assoc, strin } elseif ($val instanceof Criteria) { $qb->addCriteria($val); } elseif ($val instanceof Expression) { - $qb->addCriteria(Criteria::create(true)->where($val)); + // Doctrine Collections 2.x support + $criteria = defined(Criteria::class . '::ASC') ? Criteria::create(true) : Criteria::create(); + $qb->addCriteria($criteria->where($val)); } else { $qb->andWhere(sprintf('%s.%s = ?%s', $alias, $key, $paramIndex)); $qb->setParameter($paramIndex, $val); diff --git a/src/Codeception/Util/ReflectionPropertyAccessor.php b/src/Codeception/Util/ReflectionPropertyAccessor.php index 3882292..4fbf063 100644 --- a/src/Codeception/Util/ReflectionPropertyAccessor.php +++ b/src/Codeception/Util/ReflectionPropertyAccessor.php @@ -72,7 +72,7 @@ private function setPropertiesForClass(?object $obj, string $class, array $data) */ public function setProperties(?object $obj, array $data): void { - if (!$obj || !is_object($obj)) { + if (!is_object($obj)) { throw new InvalidArgumentException('Cannot set properties for "' . gettype($obj) . '", expecting object'); } $class = get_class($obj); diff --git a/tests/unit/Codeception/Module/Doctrine2Test.php b/tests/unit/Codeception/Module/Doctrine2Test.php index 216038d..74cfe48 100644 --- a/tests/unit/Codeception/Module/Doctrine2Test.php +++ b/tests/unit/Codeception/Module/Doctrine2Test.php @@ -9,6 +9,7 @@ use Codeception\Stub; use Codeception\Test\Unit; use Doctrine\Common\Collections\Criteria; +use Doctrine\Common\Collections\Order; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Doctrine\Common\DataFixtures\Loader; use Doctrine\Common\DataFixtures\Purger\ORMPurger; @@ -258,17 +259,17 @@ public function testCriteria() { $this->module->haveInRepository(PlainEntity::class, ['name' => 'Test 1']); $this->module->seeInRepository(PlainEntity::class, [ - Criteria::create(true)->where( + self::createCriteria()->where( Criteria::expr()->eq('name', 'Test 1') ), ]); $this->module->seeInRepository(PlainEntity::class, [ - Criteria::create(true)->where( + self::createCriteria()->where( Criteria::expr()->contains('name', 'est') ), ]); $this->module->seeInRepository(PlainEntity::class, [ - Criteria::create(true)->where( + self::createCriteria()->where( Criteria::expr()->in('name', ['Test 1']) ), ]); @@ -296,6 +297,18 @@ public function testOrderBy() $getName = fn($entity) => $entity->getName(); + $collectionsVersion = InstalledVersions::getVersion('doctrine/collections'); + if (version_compare($collectionsVersion, '3.0', '<')) { + $ascending = 'asc'; + $descending = 'desc'; + } elseif (version_compare($collectionsVersion, '3.1', '<')) { + $ascending = Order::Ascending; + $descending = Order::Descending; + } else { + $ascending = \SortDirection::Ascending; + $descending = \SortDirection::Descending; + } + $this->assertSame( [ 'a', @@ -303,7 +316,7 @@ public function testOrderBy() 'c', ], array_map($getName, $this->module->grabEntitiesFromRepository(PlainEntity::class, [ - Criteria::create(true)->orderBy(['name' => 'asc']), + self::createCriteria()->orderBy(['name' => $ascending]), ])) ); @@ -314,7 +327,7 @@ public function testOrderBy() 'a', ], array_map($getName, $this->module->grabEntitiesFromRepository(PlainEntity::class, [ - Criteria::create(true)->orderBy(['name' => 'desc']), + self::createCriteria()->orderBy(['name' => $descending]), ])) ); } @@ -597,4 +610,10 @@ public function testHaveFakeRepository() $this->assertContains($e1, $entities); $this->assertContains($e2, $entities); } + + private static function createCriteria(): Criteria + { + // Doctrine Collections 2.x support + return defined(Criteria::class . '::ASC') ? Criteria::create(true) : Criteria::create(); + } }