From 150abc11441d7cc4bac6ef7dfaf6ff8f836dd3a8 Mon Sep 17 00:00:00 2001 From: VentyCZ Date: Sun, 30 Aug 2026 17:31:38 +0200 Subject: [PATCH 1/3] Reduce PHPStan baseline: FieldDiscriminatorListener --- phpstan-baseline.php | 18 ---------- .../Listener/FieldDiscriminatorListener.php | 33 ++++++++++++++++--- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 031a5190e..4c077ae03 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2587,24 +2587,6 @@ 'count' => 1, 'path' => __DIR__ . '/src/Event/Listener/ContentFillListener.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\\\|T of object, string given\\.$#', - 'identifier' => 'argument.type', - 'count' => 1, - 'path' => __DIR__ . '/src/Event/Listener/FieldDiscriminatorListener.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Bolt\\\\Event\\\\Listener\\\\FieldDiscriminatorListener\\:\\:\\$map type has no value type specified in iterable type array\\.$#', - 'identifier' => 'missingType.iterableValue', - 'count' => 1, - 'path' => __DIR__ . '/src/Event/Listener/FieldDiscriminatorListener.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Property Bolt\\\\Event\\\\Listener\\\\FieldDiscriminatorListener\\:\\:\\$tempMap type has no value type specified in iterable type array\\.$#', - 'identifier' => 'missingType.iterableValue', - 'count' => 1, - 'path' => __DIR__ . '/src/Event/Listener/FieldDiscriminatorListener.php', -]; $ignoreErrors[] = [ 'message' => '#^Method Bolt\\\\Event\\\\Listener\\\\FieldFillListener\\:\\:clean\\(\\) has parameter \\$value with no type specified\\.$#', 'identifier' => 'missingType.parameter', diff --git a/src/Event/Listener/FieldDiscriminatorListener.php b/src/Event/Listener/FieldDiscriminatorListener.php index b6a2ed660..a42d87723 100644 --- a/src/Event/Listener/FieldDiscriminatorListener.php +++ b/src/Event/Listener/FieldDiscriminatorListener.php @@ -22,10 +22,18 @@ class FieldDiscriminatorListener { private readonly MappingDriver $mappingDriver; - /** The temporary map used for one run, when computing everything */ + /** + * The temporary map used for one run, when computing everything + * + * @var array, string> + */ private array $tempMap = []; - /** The cached map, this holds the results after a computation, also for other classes */ + /** + * The cached map, this holds the results after a computation, also for other classes + * + * @var array, array>> + */ private array $map = []; /** @@ -38,6 +46,7 @@ public function __construct(EntityManagerInterface $em) public function loadClassMetadata(LoadClassMetadataEventArgs $event): void { + /** @var class-string $className */ $className = $event->getClassMetadata()->name; if ($this->isField($className) === false) { return; @@ -59,14 +68,20 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $event): void $event->getClassMetadata()->setDiscriminatorMap($this->map[$className]); } + /** + * @param class-string $class + * @return ($class is class-string ? true : false) + */ private function isField(string $class): bool { return is_subclass_of($class, FieldInterface::class); } + /** + * @param class-string $class + */ private function extractFieldType(string $class): string { - /** @var FieldInterface $field */ $field = new $class(); $fieldType = $field->getType(); if (in_array($fieldType, $this->tempMap, true) === true) { @@ -76,6 +91,9 @@ private function extractFieldType(string $class): string return $fieldType; } + /** + * @param class-string $className + */ private function checkFamily(string $className): void { $this->tempMap[$className] = $this->extractFieldType($className); @@ -84,13 +102,20 @@ private function checkFamily(string $className): void if ($parentClass !== false) { // Also check all the parents of our child - $this->checkFamily($parentClass->name); + + /** @var class-string $parentClassName */ + $parentClassName = $parentClass->name; + + $this->checkFamily($parentClassName); } else { // Find all the children of this class $this->checkChildren($className); } } + /** + * @param class-string $parentClassName + */ private function checkChildren(string $parentClassName): void { foreach ($this->mappingDriver->getAllClassNames() as $className) { From 560dfbdd6a951a238643868499d1771118b4a5aa Mon Sep 17 00:00:00 2001 From: VentyCZ Date: Sun, 30 Aug 2026 17:37:52 +0200 Subject: [PATCH 2/3] Reduce PHPStan baseline: FieldRepository --- src/Repository/FieldRepository.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Repository/FieldRepository.php b/src/Repository/FieldRepository.php index 71174f93b..5aee284a5 100644 --- a/src/Repository/FieldRepository.php +++ b/src/Repository/FieldRepository.php @@ -96,7 +96,6 @@ public static function factory(Collection $definition, string $name = '', string $classname = self::getFieldClassname($type); if ($classname && class_exists($classname)) { - /** @var Field $field */ $field = new $classname(); } else { $field = new Field(); @@ -121,11 +120,15 @@ public static function factory(Collection $definition, string $name = '', string return $field; } + /** + * @return ?class-string + */ public static function getFieldClassname(string $type): ?string { // The classname we want $classname = ucwords($type) . 'Field'; + /** @var array> $classes */ $classes = array_map( fn (ClassMetadata $entity): string => $entity->getName(), self::$em->getMetadataFactory()->getAllMetadata() From 004394736dbc0fda9e96f5ebe196bcf8322cb4ca Mon Sep 17 00:00:00 2001 From: VentyCZ Date: Sun, 30 Aug 2026 18:03:14 +0200 Subject: [PATCH 3/3] Fixes based on AI feedback --- src/Event/Listener/FieldDiscriminatorListener.php | 2 +- src/Repository/FieldRepository.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Event/Listener/FieldDiscriminatorListener.php b/src/Event/Listener/FieldDiscriminatorListener.php index a42d87723..cdfc0a2de 100644 --- a/src/Event/Listener/FieldDiscriminatorListener.php +++ b/src/Event/Listener/FieldDiscriminatorListener.php @@ -70,7 +70,7 @@ public function loadClassMetadata(LoadClassMetadataEventArgs $event): void /** * @param class-string $class - * @return ($class is class-string ? true : false) + * @phpstan-assert-if-true class-string $class */ private function isField(string $class): bool { diff --git a/src/Repository/FieldRepository.php b/src/Repository/FieldRepository.php index 5aee284a5..4bec9948f 100644 --- a/src/Repository/FieldRepository.php +++ b/src/Repository/FieldRepository.php @@ -121,20 +121,21 @@ public static function factory(Collection $definition, string $name = '', string } /** - * @return ?class-string + * @return class-string|null */ public static function getFieldClassname(string $type): ?string { // The classname we want $classname = ucwords($type) . 'Field'; - /** @var array> $classes */ + /** @var array $classes */ $classes = array_map( fn (ClassMetadata $entity): string => $entity->getName(), self::$em->getMetadataFactory()->getAllMetadata() ); // Classnames of all fields (classes that implement Bolt\Entity\FieldInterface) + /** @var Collection> $allFields */ $allFields = collect($classes)->filter( fn (string $class): bool => in_array(FieldInterface::class, class_implements($class), true) );