diff --git a/src/Drupal/DrupalAutoloader.php b/src/Drupal/DrupalAutoloader.php index 89d5ddb3..8fcc62d9 100644 --- a/src/Drupal/DrupalAutoloader.php +++ b/src/Drupal/DrupalAutoloader.php @@ -101,7 +101,6 @@ public function register(Container $container): void throw new RuntimeException("Unable to detect Drupal with webflo/drupal-finder."); } $this->drupalRoot = $drupalRoot; - $this->autoloader = include $drupalVendorRoot . '/autoload.php'; $this->serviceYamls['core'] = $drupalRoot . '/core/core.services.yml'; diff --git a/src/Rules/Deprecations/FieldTypeCategoryRule.php b/src/Rules/Deprecations/FieldTypeCategoryRule.php new file mode 100644 index 00000000..3f9cd3c9 --- /dev/null +++ b/src/Rules/Deprecations/FieldTypeCategoryRule.php @@ -0,0 +1,103 @@ +getResolvedPhpDoc(); + if ($phpDoc instanceof ResolvedPhpDocBlock) { + if ($this->hasFieldTypeAnnotation($phpDoc) && preg_match('/category\s?=\s?@Translation/', $phpDoc->getPhpDocString()) === 1) { + $errors[] = self::DEPRECATION_MESSAGE; + } + } + + $fieldTypeAttributes = $this->getFieldTypeAttributes($reflection); + if ($fieldTypeAttributes instanceof ReflectionAttribute) { + $arguments = $fieldTypeAttributes->getArguments(); + if (array_key_exists('category', $arguments) && $arguments['category'] instanceof TranslatableMarkup) { + $errors[] = self::DEPRECATION_MESSAGE; + } + } + + return $errors; + } + + /** + * Checks whether a PHP doc block contains a field type annotation. + * + * @param \PHPStan\PhpDoc\ResolvedPhpDocBlock $phpDoc + * The PHP doc block object. + * + * @return bool + * True if it does, otherwise false. + */ + private function hasFieldTypeAnnotation(ResolvedPhpDocBlock $phpDoc): bool + { + foreach ($phpDoc->getPhpDocNodes() as $docNode) { + foreach ($docNode->children as $childNode) { + if (($childNode instanceof PhpDocTagNode) && $childNode->name === '@FieldType') { + return true; + } + } + } + + return false; + } + + /** + * Checks whether a given class has a field type attribute. + * + * @param \PHPStan\Reflection\ClassReflection $reflection + * The class reflection object. + * + * @return ReflectionAttribute|null + * The attribute, or null. + */ + private function getFieldTypeAttributes(ClassReflection $reflection): ?ReflectionAttribute + { + try { + $nativeReflection = new ReflectionClass($reflection->getName()); + $attribute = $nativeReflection->getAttributes(FieldType::class); + } catch (ReflectionException $e) { + return null; + } + + return $attribute[0] ?? null; + } +} diff --git a/tests/fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithStringCategoryAttribute.php b/tests/fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithStringCategoryAttribute.php new file mode 100644 index 00000000..4f6e644c --- /dev/null +++ b/tests/fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithStringCategoryAttribute.php @@ -0,0 +1,26 @@ +getByType(ReflectionProvider::class) + ); + } + + /** + * @dataProvider ruleData + */ + public function testRule(string $path, array $errorMessages): void + { + $this->analyse([$path], $errorMessages); + } + + public static function ruleData(): Generator + { + if (version_compare(Drupal::VERSION, '10.2.0', '>=')) { + yield [ + __DIR__ . '/../../fixtures/drupal/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/FloatItem.php', + [], + ]; + + yield [ + __DIR__ . '/../../fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithTranslatedCategoryAnnotation.php', + [ + [ + 'Using a translatable string as a category for field type is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3375748', + 19, + ], + ] + ]; + + yield [ + __DIR__ . '/../../fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithStringCategoryAttribute.php', + [] + ]; + + yield [ + __DIR__ . '/../../fixtures/drupal/modules/phpstan_fixtures/src/Plugin/Field/FieldType/FieldTypeWithTranslatedCategoryAttribute.php', + [ + [ + 'Using a translatable string as a category for field type is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. See https://www.drupal.org/node/3375748', + 12, + ], + ] + ]; + } + } +}