diff --git a/lib/Doctrine/ORM/AbstractQuery.php b/lib/Doctrine/ORM/AbstractQuery.php index dee6e53eb25..b0ed06879c7 100644 --- a/lib/Doctrine/ORM/AbstractQuery.php +++ b/lib/Doctrine/ORM/AbstractQuery.php @@ -5,16 +5,15 @@ namespace Doctrine\ORM; use BackedEnum; -use Countable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\Common\Util\ClassUtils; use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Result; -use Doctrine\Deprecations\Deprecation; use Doctrine\ORM\Cache\Logging\CacheLogger; use Doctrine\ORM\Cache\QueryCacheKey; use Doctrine\ORM\Cache\TimestampCacheKey; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\MappingException as ORMMappingException; use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\Query\QueryException; @@ -28,13 +27,11 @@ use function array_shift; use function assert; use function count; -use function in_array; use function is_array; use function is_numeric; use function is_object; use function is_scalar; use function is_string; -use function iterator_count; use function iterator_to_array; use function ksort; use function reset; @@ -86,90 +83,71 @@ abstract class AbstractQuery * @var ArrayCollection|Parameter[] * @psalm-var ArrayCollection */ - protected $parameters; + protected ArrayCollection $parameters; /** * The user-specified ResultSetMapping to use. - * - * @var ResultSetMapping|null - */ - protected $_resultSetMapping; - - /** - * The entity manager used by this query object. - * - * @var EntityManagerInterface */ - protected $_em; + protected ?ResultSetMapping $_resultSetMapping = null; /** * The map of query hints. * * @psalm-var array */ - protected $_hints = []; + protected array $_hints = []; /** * The hydration mode. * - * @var string|int * @psalm-var string|AbstractQuery::HYDRATE_* */ - protected $_hydrationMode = self::HYDRATE_OBJECT; + protected string|int $_hydrationMode = self::HYDRATE_OBJECT; - /** @var QueryCacheProfile|null */ - protected $_queryCacheProfile; + protected ?QueryCacheProfile $_queryCacheProfile = null; /** * Whether or not expire the result cache. - * - * @var bool */ - protected $_expireResultCache = false; + protected bool $_expireResultCache = false; - /** @var QueryCacheProfile|null */ - protected $_hydrationCacheProfile; + protected ?QueryCacheProfile $_hydrationCacheProfile = null; /** * Whether to use second level cache, if available. - * - * @var bool */ - protected $cacheable = false; + protected bool $cacheable = false; - /** @var bool */ - protected $hasCache = false; + protected bool $hasCache = false; /** * Second level cache region name. - * - * @var string|null */ - protected $cacheRegion; + protected ?string $cacheRegion = null; /** * Second level query cache mode. * - * @var int|null * @psalm-var Cache::MODE_*|null */ - protected $cacheMode; + protected ?int $cacheMode = null; - /** @var CacheLogger|null */ - protected $cacheLogger; + protected ?CacheLogger $cacheLogger = null; - /** @var int */ - protected $lifetime = 0; + protected int $lifetime = 0; /** * Initializes a new instance of a class derived from AbstractQuery. */ - public function __construct(EntityManagerInterface $em) - { - $this->_em = $em; + public function __construct( + /** + * The entity manager used by this query object. + */ + protected EntityManagerInterface $em + ) { $this->parameters = new ArrayCollection(); $this->_hints = $em->getConfiguration()->getDefaultQueryHints(); - $this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled(); + $this->hasCache = $this->em->getConfiguration()->isSecondLevelCacheEnabled(); if ($this->hasCache) { $this->cacheLogger = $em->getConfiguration() @@ -181,13 +159,11 @@ public function __construct(EntityManagerInterface $em) /** * Enable/disable second level query (result) caching for this query. * - * @param bool $cacheable - * * @return $this */ - public function setCacheable($cacheable) + public function setCacheable(bool $cacheable): static { - $this->cacheable = (bool) $cacheable; + $this->cacheable = $cacheable; return $this; } @@ -195,19 +171,17 @@ public function setCacheable($cacheable) /** * @return bool TRUE if the query results are enable for second level cache, FALSE otherwise. */ - public function isCacheable() + public function isCacheable(): bool { return $this->cacheable; } /** - * @param string $cacheRegion - * * @return $this */ - public function setCacheRegion($cacheRegion) + public function setCacheRegion(string $cacheRegion): static { - $this->cacheRegion = (string) $cacheRegion; + $this->cacheRegion = $cacheRegion; return $this; } @@ -217,7 +191,7 @@ public function setCacheRegion($cacheRegion) * * @return string|null The cache region name; NULL indicates the default region. */ - public function getCacheRegion() + public function getCacheRegion(): ?string { return $this->cacheRegion; } @@ -225,15 +199,12 @@ public function getCacheRegion() /** * @return bool TRUE if the query cache and second level cache are enabled, FALSE otherwise. */ - protected function isCacheEnabled() + protected function isCacheEnabled(): bool { return $this->cacheable && $this->hasCache; } - /** - * @return int - */ - public function getLifetime() + public function getLifetime(): int { return $this->lifetime; } @@ -241,35 +212,31 @@ public function getLifetime() /** * Sets the life-time for this query into second level cache. * - * @param int $lifetime - * * @return $this */ - public function setLifetime($lifetime) + public function setLifetime(int $lifetime): static { - $this->lifetime = (int) $lifetime; + $this->lifetime = $lifetime; return $this; } /** - * @return int|null * @psalm-return Cache::MODE_*|null */ - public function getCacheMode() + public function getCacheMode(): ?int { return $this->cacheMode; } /** - * @param int $cacheMode * @psalm-param Cache::MODE_* $cacheMode * * @return $this */ - public function setCacheMode($cacheMode) + public function setCacheMode(int $cacheMode): static { - $this->cacheMode = (int) $cacheMode; + $this->cacheMode = $cacheMode; return $this; } @@ -281,39 +248,34 @@ public function setCacheMode($cacheMode) * * @return list|string SQL query */ - abstract public function getSQL(); + abstract public function getSQL(): string|array; /** * Retrieves the associated EntityManager of this Query instance. - * - * @return EntityManagerInterface */ - public function getEntityManager() + public function getEntityManager(): EntityManagerInterface { - return $this->_em; + return $this->em; } /** * Frees the resources used by the query object. * * Resets Parameters, Parameter Types and Query Hints. - * - * @return void */ - public function free() + public function free(): void { $this->parameters = new ArrayCollection(); - $this->_hints = $this->_em->getConfiguration()->getDefaultQueryHints(); + $this->_hints = $this->em->getConfiguration()->getDefaultQueryHints(); } /** * Get all defined parameters. * - * @return ArrayCollection The defined query parameters. * @psalm-return ArrayCollection */ - public function getParameters() + public function getParameters(): ArrayCollection { return $this->parameters; } @@ -325,16 +287,12 @@ public function getParameters() * * @return Parameter|null The value of the bound parameter, or NULL if not available. */ - public function getParameter($key) + public function getParameter(int|string $key): ?Parameter { - $key = Query\Parameter::normalizeName($key); + $key = Parameter::normalizeName($key); $filteredParameters = $this->parameters->filter( - static function (Query\Parameter $parameter) use ($key): bool { - $parameterName = $parameter->getName(); - - return $key === $parameterName; - } + static fn (Parameter $parameter): bool => $parameter->getName() === $key ); return ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null; @@ -348,7 +306,7 @@ static function (Query\Parameter $parameter) use ($key): bool { * * @return $this */ - public function setParameters($parameters) + public function setParameters(ArrayCollection|array $parameters): static { if (is_array($parameters)) { /** @psalm-var ArrayCollection $parameterCollection */ @@ -377,7 +335,7 @@ public function setParameters($parameters) * * @return $this */ - public function setParameter($key, $value, $type = null) + public function setParameter(string|int $key, mixed $value, string|int|null $type = null): static { $existingParameter = $this->getParameter($key); @@ -395,13 +353,9 @@ public function setParameter($key, $value, $type = null) /** * Processes an individual parameter value. * - * @param mixed $value - * - * @return mixed - * * @throws ORMInvalidArgumentException */ - public function processParameterValue($value) + public function processParameterValue(mixed $value): mixed { if (is_scalar($value)) { return $value; @@ -417,7 +371,7 @@ public function processParameterValue($value) return $value; } - if ($value instanceof Mapping\ClassMetadata) { + if ($value instanceof ClassMetadata) { return $value->name; } @@ -431,12 +385,12 @@ public function processParameterValue($value) try { $class = ClassUtils::getClass($value); - $value = $this->_em->getUnitOfWork()->getSingleIdentifierValue($value); + $value = $this->em->getUnitOfWork()->getSingleIdentifierValue($value); if ($value === null) { throw ORMInvalidArgumentException::invalidIdentifierBindingEntity($class); } - } catch (MappingException | ORMMappingException $e) { + } catch (MappingException | ORMMappingException) { /* Silence any mapping exceptions. These can occur if the object in question is not a mapped entity, in which case we just don't do any preparation on the value. @@ -451,12 +405,8 @@ public function processParameterValue($value) /** * If no mapping is detected, trying to resolve the value as a Traversable - * - * @param mixed $value - * - * @return mixed */ - private function potentiallyProcessIterable($value) + private function potentiallyProcessIterable(mixed $value): mixed { if ($value instanceof Traversable) { $value = iterator_to_array($value); @@ -488,7 +438,7 @@ private function processArrayParameterValue(array $value): array * * @return $this */ - public function setResultSetMapping(Query\ResultSetMapping $rsm) + public function setResultSetMapping(ResultSetMapping $rsm): static { $this->translateNamespaces($rsm); $this->_resultSetMapping = $rsm; @@ -498,10 +448,8 @@ public function setResultSetMapping(Query\ResultSetMapping $rsm) /** * Gets the ResultSetMapping used for hydration. - * - * @return ResultSetMapping|null */ - protected function getResultSetMapping() + protected function getResultSetMapping(): ?ResultSetMapping { return $this->_resultSetMapping; } @@ -509,11 +457,9 @@ protected function getResultSetMapping() /** * Allows to translate entity namespaces to full qualified names. */ - private function translateNamespaces(Query\ResultSetMapping $rsm): void + private function translateNamespaces(ResultSetMapping $rsm): void { - $translate = function ($alias): string { - return $this->_em->getClassMetadata($alias)->getName(); - }; + $translate = fn ($alias): string => $this->em->getClassMetadata($alias)->getName(); $rsm->aliasMap = array_map($translate, $rsm->aliasMap); $rsm->declaringClasses = array_map($translate, $rsm->declaringClasses); @@ -539,7 +485,7 @@ private function translateNamespaces(Query\ResultSetMapping $rsm): void * $query->setHydrationCacheProfile(new QueryCacheProfile()); * $query->setHydrationCacheProfile(new QueryCacheProfile($lifetime, $resultKey)); */ - public function setHydrationCacheProfile(?QueryCacheProfile $profile) + public function setHydrationCacheProfile(?QueryCacheProfile $profile): static { if ($profile === null) { $this->_hydrationCacheProfile = null; @@ -548,7 +494,7 @@ public function setHydrationCacheProfile(?QueryCacheProfile $profile) } if (! $profile->getResultCache()) { - $defaultHydrationCacheImpl = $this->_em->getConfiguration()->getHydrationCache(); + $defaultHydrationCacheImpl = $this->em->getConfiguration()->getHydrationCache(); if ($defaultHydrationCacheImpl) { $profile = $profile->setResultCache($defaultHydrationCacheImpl); } @@ -559,10 +505,7 @@ public function setHydrationCacheProfile(?QueryCacheProfile $profile) return $this; } - /** - * @return QueryCacheProfile|null - */ - public function getHydrationCacheProfile() + public function getHydrationCacheProfile(): ?QueryCacheProfile { return $this->_hydrationCacheProfile; } @@ -575,7 +518,7 @@ public function getHydrationCacheProfile() * * @return $this */ - public function setResultCacheProfile(?QueryCacheProfile $profile) + public function setResultCacheProfile(?QueryCacheProfile $profile): static { if ($profile === null) { $this->_queryCacheProfile = null; @@ -584,7 +527,7 @@ public function setResultCacheProfile(?QueryCacheProfile $profile) } if (! $profile->getResultCache()) { - $defaultResultCache = $this->_em->getConfiguration()->getResultCache(); + $defaultResultCache = $this->em->getConfiguration()->getResultCache(); if ($defaultResultCache) { $profile = $profile->setResultCache($defaultResultCache); } @@ -597,10 +540,8 @@ public function setResultCacheProfile(?QueryCacheProfile $profile) /** * Defines a cache driver to be used for caching result sets and implicitly enables caching. - * - * @return $this */ - public function setResultCache(?CacheItemPoolInterface $resultCache) + public function setResultCache(?CacheItemPoolInterface $resultCache): static { if ($resultCache === null) { if ($this->_queryCacheProfile) { @@ -626,7 +567,7 @@ public function setResultCache(?CacheItemPoolInterface $resultCache) * * @return $this */ - public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null): self + public function enableResultCache(?int $lifetime = null, ?string $resultCacheId = null): static { $this->setResultCacheLifetime($lifetime); $this->setResultCacheId($resultCacheId); @@ -639,7 +580,7 @@ public function enableResultCache(?int $lifetime = null, ?string $resultCacheId * * @return $this */ - public function disableResultCache(): self + public function disableResultCache(): static { $this->_queryCacheProfile = null; @@ -653,7 +594,7 @@ public function disableResultCache(): self * * @return $this */ - public function setResultCacheLifetime($lifetime) + public function setResultCacheLifetime(?int $lifetime): static { $lifetime = (int) $lifetime; @@ -665,7 +606,7 @@ public function setResultCacheLifetime($lifetime) $this->_queryCacheProfile = new QueryCacheProfile($lifetime); - $cache = $this->_em->getConfiguration()->getResultCache(); + $cache = $this->em->getConfiguration()->getResultCache(); if (! $cache) { return $this; } @@ -682,7 +623,7 @@ public function setResultCacheLifetime($lifetime) * * @return $this */ - public function expireResultCache($expire = true) + public function expireResultCache(bool $expire = true): static { $this->_expireResultCache = $expire; @@ -691,18 +632,13 @@ public function expireResultCache($expire = true) /** * Retrieves if the resultset cache is active or not. - * - * @return bool */ - public function getExpireResultCache() + public function getExpireResultCache(): bool { return $this->_expireResultCache; } - /** - * @return QueryCacheProfile|null - */ - public function getQueryCacheProfile() + public function getQueryCacheProfile(): ?QueryCacheProfile { return $this->_queryCacheProfile; } @@ -711,24 +647,10 @@ public function getQueryCacheProfile() * Change the default fetch mode of an association for this query. * * @param class-string $class - * @param string $assocName - * @param int $fetchMode * @psalm-param Mapping\ClassMetadata::FETCH_EAGER|Mapping\ClassMetadata::FETCH_LAZY $fetchMode - * - * @return $this */ - public function setFetchMode($class, $assocName, $fetchMode) + public function setFetchMode(string $class, string $assocName, int $fetchMode): static { - if (! in_array($fetchMode, [Mapping\ClassMetadata::FETCH_EAGER, Mapping\ClassMetadata::FETCH_LAZY], true)) { - Deprecation::trigger( - 'doctrine/orm', - 'https://github.com/doctrine/orm/pull/9777', - 'Calling %s() with something else than ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY is deprecated.', - __METHOD__ - ); - $fetchMode = Mapping\ClassMetadata::FETCH_LAZY; - } - $this->_hints['fetchMode'][$class][$assocName] = $fetchMode; return $this; @@ -743,7 +665,7 @@ public function setFetchMode($class, $assocName, $fetchMode) * * @return $this */ - public function setHydrationMode($hydrationMode) + public function setHydrationMode(string|int $hydrationMode): static { $this->_hydrationMode = $hydrationMode; @@ -753,10 +675,9 @@ public function setHydrationMode($hydrationMode) /** * Gets the hydration mode currently used by the query. * - * @return string|int * @psalm-return string|AbstractQuery::HYDRATE_* */ - public function getHydrationMode() + public function getHydrationMode(): string|int { return $this->_hydrationMode; } @@ -766,12 +687,9 @@ public function getHydrationMode() * * Alias for execute(null, $hydrationMode = HYDRATE_OBJECT). * - * @param string|int $hydrationMode * @psalm-param string|AbstractQuery::HYDRATE_* $hydrationMode - * - * @return mixed */ - public function getResult($hydrationMode = self::HYDRATE_OBJECT) + public function getResult(string|int $hydrationMode = self::HYDRATE_OBJECT): mixed { return $this->execute(null, $hydrationMode); } @@ -783,7 +701,7 @@ public function getResult($hydrationMode = self::HYDRATE_OBJECT) * * @return mixed[] */ - public function getArrayResult() + public function getArrayResult(): array { return $this->execute(null, self::HYDRATE_ARRAY); } @@ -795,7 +713,7 @@ public function getArrayResult() * * @return mixed[] */ - public function getSingleColumnResult() + public function getSingleColumnResult(): array { return $this->execute(null, self::HYDRATE_SCALAR_COLUMN); } @@ -807,7 +725,7 @@ public function getSingleColumnResult() * * @return mixed[] */ - public function getScalarResult() + public function getScalarResult(): array { return $this->execute(null, self::HYDRATE_SCALAR); } @@ -815,18 +733,15 @@ public function getScalarResult() /** * Get exactly one result or null. * - * @param string|int|null $hydrationMode * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode * - * @return mixed - * * @throws NonUniqueResultException */ - public function getOneOrNullResult($hydrationMode = null) + public function getOneOrNullResult(string|int|null $hydrationMode = null): mixed { try { $result = $this->execute(null, $hydrationMode); - } catch (NoResultException $e) { + } catch (NoResultException) { return null; } @@ -853,15 +768,12 @@ public function getOneOrNullResult($hydrationMode = null) * If the result is not unique, a NonUniqueResultException is thrown. * If there is no result, a NoResultException is thrown. * - * @param string|int|null $hydrationMode * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode * - * @return mixed - * * @throws NonUniqueResultException If the query result is not unique. * @throws NoResultException If the query returned no result. */ - public function getSingleResult($hydrationMode = null) + public function getSingleResult(string|int|null $hydrationMode = null): mixed { $result = $this->execute(null, $hydrationMode); @@ -885,12 +797,10 @@ public function getSingleResult($hydrationMode = null) * * Alias for getSingleResult(HYDRATE_SINGLE_SCALAR). * - * @return mixed The scalar result. - * * @throws NoResultException If the query returned no result. * @throws NonUniqueResultException If the query result is not unique. */ - public function getSingleScalarResult() + public function getSingleScalarResult(): mixed { return $this->getSingleResult(self::HYDRATE_SINGLE_SCALAR); } @@ -898,12 +808,9 @@ public function getSingleScalarResult() /** * Sets a query hint. If the hint name is not recognized, it is silently ignored. * - * @param string $name The name of the hint. - * @param mixed $value The value of the hint. - * * @return $this */ - public function setHint($name, $value) + public function setHint(string $name, mixed $value): static { $this->_hints[$name] = $value; @@ -913,23 +820,14 @@ public function setHint($name, $value) /** * Gets the value of a query hint. If the hint name is not recognized, FALSE is returned. * - * @param string $name The name of the hint. - * * @return mixed The value of the hint or FALSE, if the hint name is not recognized. */ - public function getHint($name) + public function getHint(string $name): mixed { return $this->_hints[$name] ?? false; } - /** - * Check if the query has a hint - * - * @param string $name The name of the hint - * - * @return bool False if the query does not have any hint - */ - public function hasHint($name) + public function hasHint(string $name): bool { return isset($this->_hints[$name]); } @@ -939,7 +837,7 @@ public function hasHint($name) * * @return array */ - public function getHints() + public function getHints(): array { return $this->_hints; } @@ -948,23 +846,20 @@ public function getHints() * Executes the query and returns an iterable that can be used to incrementally * iterate over the result. * - * @param ArrayCollection|array|mixed[] $parameters The query parameters. - * @param string|int|null $hydrationMode The hydration mode to use. * @psalm-param ArrayCollection|mixed[] $parameters * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode * * @return iterable */ - public function toIterable(iterable $parameters = [], $hydrationMode = null): iterable - { + public function toIterable( + ArrayCollection|array $parameters = [], + string|int|null $hydrationMode = null + ): iterable { if ($hydrationMode !== null) { $this->setHydrationMode($hydrationMode); } - if ( - ($this->isCountable($parameters) && count($parameters) !== 0) - || ($parameters instanceof Traversable && iterator_count($parameters) !== 0) - ) { + if (count($parameters) !== 0) { $this->setParameters($parameters); } @@ -979,21 +874,19 @@ public function toIterable(iterable $parameters = [], $hydrationMode = null): it $stmt = $this->_doExecute(); - return $this->_em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints); + return $this->em->newHydrator($this->_hydrationMode)->toIterable($stmt, $rsm, $this->_hints); } /** * Executes the query. * - * @param ArrayCollection|mixed[]|null $parameters Query parameters. - * @param string|int|null $hydrationMode Processing mode to be used during the hydration process. * @psalm-param ArrayCollection|mixed[]|null $parameters * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @return mixed */ - public function execute($parameters = null, $hydrationMode = null) - { + public function execute( + ArrayCollection|array|null $parameters = null, + string|int|null $hydrationMode = null + ): mixed { if ($this->cacheable && $this->isCacheEnabled()) { return $this->executeUsingQueryCache($parameters, $hydrationMode); } @@ -1004,15 +897,13 @@ public function execute($parameters = null, $hydrationMode = null) /** * Execute query ignoring second level cache. * - * @param ArrayCollection|mixed[]|null $parameters - * @param string|int|null $hydrationMode * @psalm-param ArrayCollection|mixed[]|null $parameters * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @return mixed */ - private function executeIgnoreQueryCache($parameters = null, $hydrationMode = null) - { + private function executeIgnoreQueryCache( + ArrayCollection|array|null $parameters = null, + string|int|null $hydrationMode = null + ): mixed { if ($hydrationMode !== null) { $this->setHydrationMode($hydrationMode); } @@ -1057,7 +948,7 @@ private function executeIgnoreQueryCache($parameters = null, $hydrationMode = nu throw new LogicException('Uninitialized result set mapping.'); } - $data = $this->_em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints); + $data = $this->em->newHydrator($this->_hydrationMode)->hydrateAll($stmt, $rsm, $this->_hints); $setCacheEntry($data); @@ -1077,21 +968,19 @@ private function getHydrationCache(): CacheItemPoolInterface /** * Load from second level cache or executes the query and put into cache. * - * @param ArrayCollection|mixed[]|null $parameters - * @param string|int|null $hydrationMode * @psalm-param ArrayCollection|mixed[]|null $parameters * @psalm-param string|AbstractQuery::HYDRATE_*|null $hydrationMode - * - * @return mixed */ - private function executeUsingQueryCache($parameters = null, $hydrationMode = null) - { + private function executeUsingQueryCache( + ArrayCollection|array|null $parameters = null, + string|int|null $hydrationMode = null + ): mixed { $rsm = $this->getResultSetMapping(); if ($rsm === null) { throw new LogicException('Uninitialized result set mapping.'); } - $queryCache = $this->_em->getCache()->getQueryCache($this->cacheRegion); + $queryCache = $this->em->getCache()->getQueryCache($this->cacheRegion); $queryKey = new QueryCacheKey( $this->getHash(), $this->lifetime, @@ -1132,9 +1021,9 @@ private function getTimestampKey(): ?TimestampCacheKey return null; } - $metadata = $this->_em->getClassMetadata($entityName); + $metadata = $this->em->getClassMetadata($entityName); - return new Cache\TimestampCacheKey($metadata->rootEntityName); + return new TimestampCacheKey($metadata->rootEntityName); } /** @@ -1145,7 +1034,7 @@ private function getTimestampKey(): ?TimestampCacheKey * @return string[] ($key, $hash) * @psalm-return array{string, string} ($key, $hash) */ - protected function getHydrationCacheId() + protected function getHydrationCacheId(): array { $parameters = []; @@ -1169,12 +1058,8 @@ protected function getHydrationCacheId() * Set the result cache id to use to store the result set cache entry. * If this is not explicitly set by the developer then a hash is automatically * generated for you. - * - * @param string|null $id - * - * @return $this */ - public function setResultCacheId($id) + public function setResultCacheId(?string $id): static { if (! $this->_queryCacheProfile) { return $this->setResultCacheProfile(new QueryCacheProfile(0, $id)); @@ -1192,27 +1077,23 @@ public function setResultCacheId($id) * the results, or an integer indicating how * many rows were affected. */ - abstract protected function _doExecute(); + abstract protected function _doExecute(): Result|int; /** * Cleanup Query resource when clone is called. - * - * @return void */ public function __clone() { $this->parameters = new ArrayCollection(); $this->_hints = []; - $this->_hints = $this->_em->getConfiguration()->getDefaultQueryHints(); + $this->_hints = $this->em->getConfiguration()->getDefaultQueryHints(); } /** * Generates a string of currently query to use for the cache second level cache. - * - * @return string */ - protected function getHash() + protected function getHash(): string { $query = $this->getSQL(); assert(is_string($query)); @@ -1233,10 +1114,4 @@ protected function getHash() return sha1($query . '-' . serialize($params) . '-' . serialize($hints)); } - - /** @param iterable $subject */ - private function isCountable(iterable $subject): bool - { - return $subject instanceof Countable || is_array($subject); - } } diff --git a/lib/Doctrine/ORM/NativeQuery.php b/lib/Doctrine/ORM/NativeQuery.php index 65925cbe1e9..97ba4c87c33 100644 --- a/lib/Doctrine/ORM/NativeQuery.php +++ b/lib/Doctrine/ORM/NativeQuery.php @@ -4,6 +4,9 @@ namespace Doctrine\ORM; +use Doctrine\DBAL\Result; +use Doctrine\ORM\Query\ParameterTypeInferer; + use function array_values; use function is_int; use function key; @@ -14,35 +17,24 @@ */ final class NativeQuery extends AbstractQuery { - /** @var string */ - private $sql; + private string $sql; /** - * Sets the SQL of the query. - * - * @param string $sql - * * @return $this */ - public function setSQL($sql): self + public function setSQL(string $sql): self { $this->sql = $sql; return $this; } - /** - * Gets the SQL query. - */ public function getSQL(): string { return $this->sql; } - /** - * {@inheritdoc} - */ - protected function _doExecute() + protected function _doExecute(): Result|int { $parameters = []; $types = []; @@ -52,7 +44,7 @@ protected function _doExecute() $value = $this->processParameterValue($parameter->getValue()); $type = $parameter->getValue() === $value ? $parameter->getType() - : Query\ParameterTypeInferer::inferType($value); + : ParameterTypeInferer::inferType($value); $parameters[$name] = $value; $types[$name] = $type; @@ -66,7 +58,7 @@ protected function _doExecute() $types = array_values($types); } - return $this->_em->getConnection()->executeQuery( + return $this->em->getConnection()->executeQuery( $this->sql, $parameters, $types, diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 046257b599b..222308ae017 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -5,6 +5,7 @@ namespace Doctrine\ORM; use Doctrine\DBAL\LockMode; +use Doctrine\DBAL\Result; use Doctrine\DBAL\Types\Type; use Doctrine\Deprecations\Deprecation; use Doctrine\ORM\Mapping\ClassMetadata; @@ -112,102 +113,78 @@ final class Query extends AbstractQuery /** * The current state of this query. * - * @var int * @psalm-var self::STATE_* */ - private $_state = self::STATE_DIRTY; + private int $_state = self::STATE_DIRTY; /** * A snapshot of the parameter types the query was parsed with. * * @var array */ - private $parsedTypes = []; + private array $parsedTypes = []; /** * Cached DQL query. - * - * @var string|null */ - private $dql = null; + private ?string $dql = null; /** * The parser result that holds DQL => SQL information. - * - * @var ParserResult */ - private $parserResult; + private ParserResult $parserResult; /** * The first result to return (the "offset"). - * - * @var int */ - private $firstResult = 0; + private int $firstResult = 0; /** * The maximum number of results to return (the "limit"). - * - * @var int|null */ - private $maxResults = null; + private ?int $maxResults = null; /** * The cache driver used for caching queries. - * - * @var CacheItemPoolInterface|null */ - private $queryCache; + private ?CacheItemPoolInterface $queryCache = null; /** * Whether or not expire the query cache. - * - * @var bool */ - private $expireQueryCache = false; + private bool $expireQueryCache = false; /** * The query cache lifetime. - * - * @var int|null */ - private $queryCacheTTL; + private ?int $queryCacheTTL = null; /** * Whether to use a query cache, if available. Defaults to TRUE. - * - * @var bool */ - private $useQueryCache = true; + private bool $useQueryCache = true; /** * Gets the SQL query/queries that correspond to this DQL query. * * @return list|string The built sql query or an array of all sql queries. */ - public function getSQL() + public function getSQL(): string|array { return $this->parse()->getSqlExecutor()->getSqlStatements(); } /** * Returns the corresponding AST for this DQL query. - * - * @return SelectStatement|UpdateStatement|DeleteStatement */ - public function getAST() + public function getAST(): SelectStatement|UpdateStatement|DeleteStatement { $parser = new Parser($this); return $parser->getAST(); } - /** - * {@inheritdoc} - * - * @return ResultSetMapping - */ - protected function getResultSetMapping() + protected function getResultSetMapping(): ResultSetMapping { // parse query or load from cache if ($this->_resultSetMapping === null) { @@ -232,14 +209,14 @@ private function parse(): ParserResult } // Return previous parser result if the query and the filter collection are both clean - if ($this->_state === self::STATE_CLEAN && $this->parsedTypes === $types && $this->_em->isFiltersStateClean()) { + if ($this->_state === self::STATE_CLEAN && $this->parsedTypes === $types && $this->em->isFiltersStateClean()) { return $this->parserResult; } $this->_state = self::STATE_CLEAN; $this->parsedTypes = $types; - $queryCache = $this->queryCache ?? $this->_em->getConfiguration()->getQueryCache(); + $queryCache = $this->queryCache ?? $this->em->getConfiguration()->getQueryCache(); // Check query cache. if (! ($this->useQueryCache && $queryCache)) { $parser = new Parser($this); @@ -271,10 +248,7 @@ private function parse(): ParserResult return $this->parserResult; } - /** - * {@inheritdoc} - */ - protected function _doExecute() + protected function _doExecute(): Result|int { $executor = $this->parse()->getSqlExecutor(); @@ -312,10 +286,10 @@ protected function _doExecute() $executor, $sqlParams, $types, - $this->_em->getConnection()->getParams() + $this->em->getConnection()->getParams() ); - return $executor->execute($this->_em->getConnection(), $sqlParams, $types); + return $executor->execute($this->em->getConnection(), $sqlParams, $types); } /** @@ -360,7 +334,7 @@ private function evictEntityCacheRegion(): void ? $AST->deleteClause->abstractSchemaName : $AST->updateClause->abstractSchemaName; - $this->_em->getCache()->evictEntityRegion($className); + $this->em->getCache()->evictEntityRegion($className); } /** @@ -438,7 +412,7 @@ private function resolveParameterValue(Parameter $parameter): array } if ($value instanceof ClassMetadata && isset($rsm->discriminatorParameters[$key])) { - $value = array_keys(HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($value, $this->_em)); + $value = array_keys(HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($value, $this->em)); } $processedValue = $this->processParameterValue($value); @@ -466,11 +440,9 @@ public function setQueryCache(?CacheItemPoolInterface $queryCache): self /** * Defines whether the query should make use of a query cache, if available. * - * @param bool $bool - * * @return $this */ - public function useQueryCache($bool): self + public function useQueryCache(bool $bool): self { $this->useQueryCache = $bool; @@ -484,12 +456,8 @@ public function useQueryCache($bool): self * * @return $this */ - public function setQueryCacheLifetime($timeToLive): self + public function setQueryCacheLifetime(?int $timeToLive): self { - if ($timeToLive !== null) { - $timeToLive = (int) $timeToLive; - } - $this->queryCacheTTL = $timeToLive; return $this; @@ -506,11 +474,9 @@ public function getQueryCacheLifetime(): ?int /** * Defines if the query cache is active or not. * - * @param bool $expire Whether or not to force query cache expiration. - * * @return $this */ - public function expireQueryCache($expire = true): self + public function expireQueryCache(bool $expire = true): self { $this->expireQueryCache = $expire; @@ -535,10 +501,8 @@ public function free(): void /** * Sets a DQL query string. - * - * @param string|null $dqlQuery DQL Query. */ - public function setDQL($dqlQuery): self + public function setDQL(?string $dqlQuery): self { if ($dqlQuery === null) { Deprecation::trigger( @@ -586,7 +550,7 @@ public function getState(): int * * @param string $dql Arbitrary piece of DQL to check for. */ - public function contains($dql): bool + public function contains(string $dql): bool { return stripos($this->getDQL(), $dql) !== false; } @@ -598,7 +562,7 @@ public function contains($dql): bool * * @return $this */ - public function setFirstResult($firstResult): self + public function setFirstResult(?int $firstResult): self { if (! is_int($firstResult)) { Deprecation::trigger( @@ -632,16 +596,10 @@ public function getFirstResult(): ?int /** * Sets the maximum number of results to retrieve (the "limit"). * - * @param int|null $maxResults - * * @return $this */ - public function setMaxResults($maxResults): self + public function setMaxResults(?int $maxResults): self { - if ($maxResults !== null) { - $maxResults = (int) $maxResults; - } - $this->maxResults = $maxResults; $this->_state = self::STATE_DIRTY; @@ -667,20 +625,14 @@ public function toIterable(iterable $parameters = [], $hydrationMode = self::HYD return parent::toIterable($parameters, $hydrationMode); } - /** - * {@inheritdoc} - */ - public function setHint($name, $value): self + public function setHint(string $name, mixed $value): static { $this->_state = self::STATE_DIRTY; return parent::setHint($name, $value); } - /** - * {@inheritdoc} - */ - public function setHydrationMode($hydrationMode): self + public function setHydrationMode(string|int $hydrationMode): static { $this->_state = self::STATE_DIRTY; @@ -692,15 +644,14 @@ public function setHydrationMode($hydrationMode): self * * @see \Doctrine\DBAL\LockMode * - * @param int $lockMode * @psalm-param LockMode::* $lockMode * * @throws TransactionRequiredException */ - public function setLockMode($lockMode): self + public function setLockMode(int $lockMode): self { if (in_array($lockMode, [LockMode::NONE, LockMode::PESSIMISTIC_READ, LockMode::PESSIMISTIC_WRITE], true)) { - if (! $this->_em->getConnection()->isTransactionActive()) { + if (! $this->em->getConnection()->isTransactionActive()) { throw TransactionRequiredException::transactionRequired(); } } @@ -736,7 +687,7 @@ protected function getQueryCacheId(): string return md5( $this->getDQL() . serialize($this->_hints) . '&platform=' . get_debug_type($this->getEntityManager()->getConnection()->getDatabasePlatform()) . - ($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') . + ($this->em->hasFilters() ? $this->em->getFilters()->getHash() : '') . '&firstResult=' . $this->firstResult . '&maxResult=' . $this->maxResults . '&hydrationMode=' . $this->_hydrationMode . '&types=' . serialize($this->parsedTypes) . 'DOCTRINE_QUERY_CACHE_SALT' ); diff --git a/psalm-baseline.xml b/psalm-baseline.xml index a142a56e010..3a222ab7f77 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,9 +1,6 @@ - - in_array($fetchMode, [Mapping\ClassMetadata::FETCH_EAGER, Mapping\ClassMetadata::FETCH_LAZY], true) - ! $filteredParameters->isEmpty() ? $filteredParameters->first() : null @@ -22,12 +19,6 @@ getCacheLogger getQueryCache - - (bool) $cacheable - (int) $cacheMode - (int) $lifetime - (string) $cacheRegion - @@ -1168,14 +1159,6 @@ $sqlParams - - parent::setHint($name, $value) - parent::setHydrationMode($hydrationMode) - - - self - self - $this->getDQL() diff --git a/tests/Doctrine/Tests/ORM/AbstractQueryTest.php b/tests/Doctrine/Tests/ORM/AbstractQueryTest.php index 93adc309636..0f3738c0c6e 100644 --- a/tests/Doctrine/Tests/ORM/AbstractQueryTest.php +++ b/tests/Doctrine/Tests/ORM/AbstractQueryTest.php @@ -6,18 +6,14 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Result; -use Doctrine\Deprecations\PHPUnit\VerifyDeprecations; use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManagerInterface; use PHPUnit\Framework\TestCase; use Psr\Cache\CacheItemPoolInterface; -use stdClass; final class AbstractQueryTest extends TestCase { - use VerifyDeprecations; - public function testItMakesHydrationCacheProfilesAwareOfTheResultCache(): void { $cache = $this->createMock(CacheItemPoolInterface::class); @@ -58,18 +54,6 @@ public function testSettingTheResultCacheIsPossibleWithoutCallingDeprecatedMetho self::assertSame($cache, $query->getResultCache()); } - - public function testSettingTheFetchModeToRandomIntegersIsDeprecated(): void - { - $query = $this->getMockForAbstractClass( - AbstractQuery::class, - [], - '', - false // no need to call the constructor - ); - $this->expectDeprecationWithIdentifier('https://github.com/doctrine/orm/pull/9777'); - $query->setFetchMode(stdClass::class, 'foo', 42); - } } class TestQuery extends AbstractQuery