From 6c7a5e6faa72bd48b31d891850615c81185ab651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Fri, 11 Nov 2022 18:22:17 +0100 Subject: [PATCH 1/5] Document property as non-nullable The constructor forbids it. --- lib/Doctrine/ORM/Query/AST/WhenClause.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Query/AST/WhenClause.php b/lib/Doctrine/ORM/Query/AST/WhenClause.php index 7d9fbf49399..504a5e276ad 100644 --- a/lib/Doctrine/ORM/Query/AST/WhenClause.php +++ b/lib/Doctrine/ORM/Query/AST/WhenClause.php @@ -12,7 +12,7 @@ class WhenClause extends Node { /** @var ConditionalExpression */ - public $caseConditionExpression = null; + public $caseConditionExpression; /** @var mixed */ public $thenScalarExpression = null; From 3178b4ec4fc2a71872d968091a1a39ca7b53c086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 13 Nov 2022 19:03:22 +0100 Subject: [PATCH 2/5] Widen parameter type This exception is used in two places, one where $generatedMode is clearly a string, and another where typing it as a string will cause a type error, because $generatedMode is supposed to be an int there. --- lib/Doctrine/ORM/Mapping/MappingException.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index 875f9f07594..2d069cdc420 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -824,7 +824,8 @@ 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 + /** @param int|string $annotation */ + public static function invalidGeneratedMode($annotation): MappingException { return new self("Invalid generated mode '" . $annotation . "'"); } From 843f3c3b239337209f7646c730f94827768846b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 13 Nov 2022 11:21:11 +0100 Subject: [PATCH 3/5] Make the code easier to statically analyse --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 15 ++++++++++----- .../ORM/Mapping/Driver/DatabaseDriver.php | 2 +- lib/Doctrine/ORM/Query/Expr.php | 14 ++++++++------ lib/Doctrine/ORM/Query/Parser.php | 2 +- .../ORM/Tools/Console/Command/RunDqlCommand.php | 2 +- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index 955c3993f0a..9be1b0176bd 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -1574,9 +1574,9 @@ private function isTypedProperty(string $name): bool /** * Validates & completes the given field mapping based on typed property. * - * @param mixed[] $mapping The field mapping to validate & complete. + * @param array{fieldName: string, type?: mixed} $mapping The field mapping to validate & complete. * - * @return mixed[] The updated mapping. + * @return array{fieldName: string, enumType?: string, type?: mixed} The updated mapping. */ private function validateAndCompleteTypedFieldMapping(array $mapping): array { @@ -1631,7 +1631,7 @@ private function validateAndCompleteTypedFieldMapping(array $mapping): array /** * Validates & completes the basic mapping information based on typed property. * - * @param mixed[] $mapping The mapping. + * @param array{type: self::ONE_TO_ONE|self::MANY_TO_ONE|self::ONE_TO_MANY|self::MANY_TO_MANY, fieldName: string, targetEntity?: class-string} $mapping The mapping. * * @return mixed[] The updated mapping. */ @@ -1653,7 +1653,13 @@ private function validateAndCompleteTypedAssociationMapping(array $mapping): arr /** * Validates & completes the given field mapping. * - * @psalm-param array $mapping The field mapping to validate & complete. + * @psalm-param array{ + * fieldName?: string, + * columnName?: string, + * id?: bool, + * generated?: int, + * enumType?: class-string, + * } $mapping The field mapping to validate & complete. * * @return mixed[] The updated mapping. * @@ -1897,7 +1903,6 @@ protected function _validateAndCompleteAssociationMapping(array $mapping) * Validates & completes a one-to-one association mapping. * * @psalm-param array $mapping The mapping to validate & complete. - * @psalm-param array $mapping The mapping to validate & complete. * * @return mixed[] The validated & completed mapping. * @psalm-return array{isOwningSide: mixed, orphanRemoval: bool, isCascadeRemove: bool} diff --git a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php index 952ed821656..bf9e27c87ea 100644 --- a/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php +++ b/lib/Doctrine/ORM/Mapping/Driver/DatabaseDriver.php @@ -66,7 +66,7 @@ class DatabaseDriver implements MappingDriver /** @var array|null */ private $tables = null; - /** @var mixed[] */ + /** @var array */ private $classToTableNames = []; /** @psalm-var array */ diff --git a/lib/Doctrine/ORM/Query/Expr.php b/lib/Doctrine/ORM/Query/Expr.php index d593782a135..6c29e8061ca 100644 --- a/lib/Doctrine/ORM/Query/Expr.php +++ b/lib/Doctrine/ORM/Query/Expr.php @@ -9,9 +9,9 @@ use function func_get_args; use function implode; use function is_bool; +use function is_float; +use function is_int; use function is_iterable; -use function is_numeric; -use function is_string; use function iterator_to_array; use function str_replace; @@ -608,7 +608,7 @@ public function length($x) /** * Creates a literal expression of the given argument. * - * @param mixed $literal Argument to be converted to literal. + * @param scalar $literal Argument to be converted to literal. * * @return Expr\Literal */ @@ -620,13 +620,15 @@ public function literal($literal) /** * Quotes a literal value, if necessary, according to the DQL syntax. * - * @param mixed $literal The literal value. + * @param scalar $literal The literal value. */ private function quoteLiteral($literal): string { - if (is_numeric($literal) && ! is_string($literal)) { + if (is_int($literal) || is_float($literal)) { return (string) $literal; - } elseif (is_bool($literal)) { + } + + if (is_bool($literal)) { return $literal ? 'true' : 'false'; } diff --git a/lib/Doctrine/ORM/Query/Parser.php b/lib/Doctrine/ORM/Query/Parser.php index 75f5b3051ad..14d2ae02c5e 100644 --- a/lib/Doctrine/ORM/Query/Parser.php +++ b/lib/Doctrine/ORM/Query/Parser.php @@ -685,7 +685,7 @@ private function processDeferredNewObjectExpressions(SelectStatement $AST): void $fromClassName = $AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName ?? null; // If the namespace is not given then assumes the first FROM entity namespace - if (! str_contains($className, '\\') && ! class_exists($className) && str_contains($fromClassName, '\\')) { + if (! str_contains($className, '\\') && ! class_exists($className) && is_string($fromClassName) && str_contains($fromClassName, '\\')) { $namespace = substr($fromClassName, 0, strrpos($fromClassName, '\\')); $fqcn = $namespace . '\\' . $className; diff --git a/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php index 90801d1defb..8a0701a71cb 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php @@ -66,7 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new LogicException("Option 'depth' must contain an integer value"); } - $hydrationModeName = $input->getOption('hydrate'); + $hydrationModeName = (string) $input->getOption('hydrate'); $hydrationMode = 'Doctrine\ORM\Query::HYDRATE_' . strtoupper(str_replace('-', '_', $hydrationModeName)); if (! defined($hydrationMode)) { From 958d0b619321a0650c3ebf967911d9b6ae7c265c Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 15 Nov 2022 17:38:56 +0100 Subject: [PATCH 4/5] update help for RunDqlCommand (#10233) --- .../Tools/Console/Command/RunDqlCommand.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php index 90801d1defb..93a11de50fb 100644 --- a/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php +++ b/lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php @@ -41,7 +41,23 @@ protected function configure() ->addOption('max-result', null, InputOption::VALUE_REQUIRED, 'The maximum number of results in the result set.') ->addOption('depth', null, InputOption::VALUE_REQUIRED, 'Dumping depth of Entity graph.', 7) ->addOption('show-sql', null, InputOption::VALUE_NONE, 'Dump generated SQL instead of executing query') - ->setHelp('Executes arbitrary DQL directly from the command line.'); + ->setHelp(<<<'EOT' +The %command.name% command executes the given DQL query and +outputs the results: + +php %command.full_name% "SELECT u FROM App\Entity\User u" + +You can also optionally specify some additional options like what type of +hydration to use when executing the query: + +php %command.full_name% "SELECT u FROM App\Entity\User u" --hydrate=array + +Additionally you can specify the first result and maximum amount of results to +show: + +php %command.full_name% "SELECT u FROM App\Entity\User u" --first-result=0 --max-result=30 +EOT + ); } /** From a5a6cc6630ce497290396d5f206887227820a634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sun, 20 Nov 2022 19:53:31 +0100 Subject: [PATCH 5/5] Remove fragile assertions (#10239) RuntimePublicReflectionProperty has been deprecated in favor of RuntimeReflectionProperty. Let us use a more robust assertion. --- tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php index ea3682f1d97..a4b40d1e35e 100644 --- a/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/ValueObjectsTest.php @@ -19,8 +19,8 @@ use Doctrine\ORM\Mapping\MappingException; use Doctrine\ORM\Mapping\ReflectionEmbeddedProperty; use Doctrine\ORM\Query\QueryException; -use Doctrine\Persistence\Reflection\RuntimePublicReflectionProperty; use Doctrine\Tests\OrmFunctionalTestCase; +use ReflectionProperty; use function class_exists; use function sprintf; @@ -53,7 +53,7 @@ public function testMetadataHasReflectionEmbeddablesAccessible(): void ); } else { self::assertInstanceOf( - RuntimePublicReflectionProperty::class, + ReflectionProperty::class, $classMetadata->getReflectionProperty('address') ); }