diff --git a/README.md b/README.md index c5e349f..6bbd7fe 100644 --- a/README.md +++ b/README.md @@ -346,14 +346,14 @@ final class Alert
-### PublicPropertiesShouldBeCamelCaseRule +### PostMountMethodSignatureRule -Enforces that all public properties in Twig Components follow camelCase naming convention. -This ensures consistency and better integration with Twig templates where properties are passed and accessed using camelCase. +Enforces that methods with the `#[PostMount]` attribute have the correct signature: they must be public with an optional parameter of type `array`, and a return type of `array`, `void`, or `array|void`. +This ensures proper integration with the Symfony UX TwigComponent lifecycle hooks. ```yaml rules: - - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PublicPropertiesShouldBeCamelCaseRule + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PostMountMethodSignatureRule ``` ```php @@ -361,12 +361,15 @@ rules: namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\Attribute\PostMount; #[AsTwigComponent] final class Alert { - public string $user_name; - public bool $is_active; + #[PostMount] + protected function postMount(): void + { + } } ``` @@ -375,11 +378,33 @@ final class Alert namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\Attribute\PostMount; #[AsTwigComponent] final class Alert { - public string $UserName; + #[PostMount] + public function postMount(array $data): string + { + return 'invalid'; + } +} +``` + +```php +// src/Twig/Components/Alert.php +namespace App\Twig\Components; + +use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\Attribute\PostMount; + +#[AsTwigComponent] +final class Alert +{ + #[PostMount] + public function postMount(string $data): void + { + } } ``` @@ -392,12 +417,33 @@ final class Alert namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\Attribute\PostMount; #[AsTwigComponent] final class Alert { - public string $userName; - public bool $isActive; + #[PostMount] + public function postMount(): void + { + } +} +``` + +```php +// src/Twig/Components/Alert.php +namespace App\Twig\Components; + +use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; +use Symfony\UX\TwigComponent\Attribute\PostMount; + +#[AsTwigComponent] +final class Alert +{ + #[PostMount] + public function postMount(array $data): array + { + return $data; + } } ``` @@ -407,7 +453,7 @@ final class Alert ### PreMountMethodSignatureRule -Enforces that methods with the `#[PreMount]` attribute have the correct signature: they must be public and have exactly one parameter of type `array`, with a return type of `array`. +Enforces that methods with the `#[PreMount]` attribute have the correct signature: they must be public and have exactly one parameter of type `array`, with a return type of `array`, `void`, or `array|void` . This ensures proper integration with the Symfony UX TwigComponent lifecycle hooks. ```yaml @@ -444,12 +490,17 @@ use Symfony\UX\TwigComponent\Attribute\PreMount; final class Alert { #[PreMount] - public function preMount(array $data): void + public function preMount(string $data): array { + return []; } } ``` +:x: + +
+ ```php // src/Twig/Components/Alert.php namespace App\Twig\Components; @@ -461,34 +512,71 @@ use Symfony\UX\TwigComponent\Attribute\PreMount; final class Alert { #[PreMount] - public function preMount(string $data): array + public function preMount(array $data): array { - return []; + $data['timestamp'] = time(); + + return $data; } } ``` -:x: +:+1:
+### PublicPropertiesShouldBeCamelCaseRule + +Enforces that all public properties in Twig Components follow camelCase naming convention. +This ensures consistency and better integration with Twig templates where properties are passed and accessed using camelCase. + +```yaml +rules: + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PublicPropertiesShouldBeCamelCaseRule +``` + ```php // src/Twig/Components/Alert.php namespace App\Twig\Components; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; -use Symfony\UX\TwigComponent\Attribute\PreMount; #[AsTwigComponent] final class Alert { - #[PreMount] - public function preMount(array $data): array - { - $data['timestamp'] = time(); + public string $user_name; + public bool $is_active; +} +``` - return $data; - } +```php +// src/Twig/Components/Alert.php +namespace App\Twig\Components; + +use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; + +#[AsTwigComponent] +final class Alert +{ + public string $UserName; +} +``` + +:x: + +
+ +```php +// src/Twig/Components/Alert.php +namespace App\Twig\Components; + +use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; + +#[AsTwigComponent] +final class Alert +{ + public string $userName; + public bool $isActive; } ``` diff --git a/ecs.php b/ecs.php index 7f24063..09033eb 100644 --- a/ecs.php +++ b/ecs.php @@ -14,7 +14,7 @@ ->withPreparedSets(psr12: true, common: true) ->withSkip([ ProtectedToPrivateFixer::class => [ - __DIR__ . '/tests/Rules/TwigComponent/MethodsShouldBePublicOrPrivateRule/Fixture/*', + __DIR__ . '/tests/Rules/**/Fixture/*', ], ]) ; diff --git a/phpstan.dist.neon b/phpstan.dist.neon index e786f4c..053d645 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -12,6 +12,4 @@ parameters: identifiers: - method.unused - missingType.iterableValue - - missingType.return - property.unused - - return.unusedType \ No newline at end of file diff --git a/src/Rules/TwigComponent/PostMountMethodSignatureRule.php b/src/Rules/TwigComponent/PostMountMethodSignatureRule.php new file mode 100644 index 0000000..7623153 --- /dev/null +++ b/src/Rules/TwigComponent/PostMountMethodSignatureRule.php @@ -0,0 +1,114 @@ + + */ +final class PostMountMethodSignatureRule implements Rule +{ + public function __construct( + private ReflectionProvider $reflectionProvider, + ) { + } + + public function getNodeType(): string + { + return Class_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (! AttributeFinder::findAnyAttribute($node, [AsTwigComponent::class, AsLiveComponent::class])) { + return []; + } + + if ($node->namespacedName === null) { + return []; + } + + $errors = []; + $reflClass = $this->reflectionProvider->getClass($node->namespacedName->toString()); + + foreach ($node->getMethods() as $method) { + if (! AttributeFinder::findAttribute($method, PostMount::class)) { + continue; + } + + $errors[] = $this->validatePostMountMethod( + $method, + $reflClass->getMethod($method->name->name, $scope), + ); + } + + return array_merge(...$errors); + } + + /** + * @return list<\PHPStan\Rules\IdentifierRuleError> + */ + private function validatePostMountMethod(Node\Stmt\ClassMethod $method, ExtendedMethodReflection $reflMethod): array + { + $errors = []; + + $methodName = $reflMethod->getName(); + $methodParams = $reflMethod->getOnlyVariant()->getParameters(); + $methodReturnType = $reflMethod->getOnlyVariant()->getReturnType(); + + // Check if method is public + if (! $reflMethod->isPublic()) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PostMount] attribute must be public.', $methodName)) + ->identifier('symfonyUX.twigComponent.postMountPublic') + ->line($method->getLine()) + ->tip('Change the method visibility to public.') + ->build(); + } + + // Check parameter count and type (0 or 1 parameter allowed) + if (count($methodParams) > 1) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PostMount] attribute must have at most one parameter of type "array".', $methodName)) + ->identifier('symfonyUX.twigComponent.postMountParameterCount') + ->line($method->getLine()) + ->tip('The method should have zero or one parameter: "array $data" (optional).') + ->build(); + } elseif (count($methodParams) === 1) { + // If there is a parameter, it must be of type array + if (! $methodParams[0]->getType()->isArray()->yes()) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PostMount] attribute must have a parameter of type "array".', $methodName)) + ->identifier('symfonyUX.twigComponent.postMountParameterType') + ->line($method->getLine()) + ->tip('Change the parameter type to "array".') + ->build(); + } + } + + // Check return type (must be array, void, or array|void) + $isValidReturnType = $methodReturnType->isVoid()->yes() + || $methodReturnType->isArray()->yes() + || ($methodReturnType->isArray()->maybe() && $methodReturnType->isVoid()->maybe()); + + if (! $isValidReturnType) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PostMount] attribute must have a return type of "array", "void", or "array|void".', $methodName)) + ->identifier('symfonyUX.twigComponent.postMountReturnType') + ->line($method->getLine()) + ->tip('Change the return type to ": array", ": void", or ": array|void".') + ->build(); + } + + return $errors; + } +} diff --git a/src/Rules/TwigComponent/PreMountMethodSignatureRule.php b/src/Rules/TwigComponent/PreMountMethodSignatureRule.php index 4543c34..2223865 100644 --- a/src/Rules/TwigComponent/PreMountMethodSignatureRule.php +++ b/src/Rules/TwigComponent/PreMountMethodSignatureRule.php @@ -8,6 +8,8 @@ use PhpParser\Node; use PhpParser\Node\Stmt\Class_; use PHPStan\Analyser\Scope; +use PHPStan\Reflection\ExtendedMethodReflection; +use PHPStan\Reflection\ReflectionProvider; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleErrorBuilder; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; @@ -19,6 +21,11 @@ */ final class PreMountMethodSignatureRule implements Rule { + public function __construct( + private ReflectionProvider $reflectionProvider, + ) { + } + public function getNodeType(): string { return Class_::class; @@ -30,84 +37,76 @@ public function processNode(Node $node, Scope $scope): array return []; } + if ($node->namespacedName === null) { + return []; + } + $errors = []; + $reflClass = $this->reflectionProvider->getClass($node->namespacedName->toString()); foreach ($node->getMethods() as $method) { - // Check if the method has the PreMount attribute if (! AttributeFinder::findAttribute($method, PreMount::class)) { continue; } - $errors = array_merge($errors, $this->validatePreMountMethod($method)); + $errors[] = $this->validatePreMountMethod( + $method, + $reflClass->getMethod($method->name->name, $scope), + ); } - return $errors; + return array_merge(...$errors); } /** * @return list<\PHPStan\Rules\IdentifierRuleError> */ - private function validatePreMountMethod(Node\Stmt\ClassMethod $node): array + private function validatePreMountMethod(Node\Stmt\ClassMethod $method, ExtendedMethodReflection $reflMethod): array { $errors = []; - // Check if the method is public - if (! $node->isPublic()) { - $errors[] = RuleErrorBuilder::message( - sprintf('Method "%s" with #[PreMount] attribute must be public.', $node->name->toString()) - ) - ->identifier('symfonyUX.twigComponent.preMountMethodMustBePublic') - ->line($node->getLine()) + $methodName = $reflMethod->getName(); + $methodParams = $reflMethod->getOnlyVariant()->getParameters(); + $methodReturnType = $reflMethod->getOnlyVariant()->getReturnType(); + + // Check if method is public + if (! $reflMethod->isPublic()) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PreMount] attribute must be public.', $methodName)) + ->identifier('symfonyUX.twigComponent.preMountPublic') + ->line($method->getLine()) ->tip('Change the method visibility to public.') ->build(); } - // Check the return type - $returnType = $node->getReturnType(); - if ($returnType === null) { - $errors[] = RuleErrorBuilder::message( - sprintf('Method "%s" with #[PreMount] attribute must have a return type of "array".', $node->name->toString()) - ) - ->identifier('symfonyUX.twigComponent.preMountMethodMissingReturnType') - ->line($node->getLine()) - ->tip('Add ": array" return type to the method.') + // Check parameter count and type (0 or 1 parameter allowed) + if (count($methodParams) > 1) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PreMount] attribute must have at most one parameter of type "array".', $methodName)) + ->identifier('symfonyUX.twigComponent.preMountParameterCount') + ->line($method->getLine()) + ->tip('The method should have zero or one parameter: "array $data" (optional).') ->build(); - } else { - $isValidReturnType = $returnType instanceof Node\Identifier && $returnType->toString() === 'array'; - - if (! $isValidReturnType) { - $errors[] = RuleErrorBuilder::message( - sprintf('Method "%s" with #[PreMount] attribute must have a return type of "array".', $node->name->toString()) - ) - ->identifier('symfonyUX.twigComponent.preMountMethodInvalidReturnType') - ->line($returnType->getLine()) - ->tip('Change the return type to ": array".') + } elseif (count($methodParams) === 1) { + // If there is a parameter, it must be of type array + if (! $methodParams[0]->getType()->isArray()->yes()) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PreMount] attribute must have a parameter of type "array".', $methodName)) + ->identifier('symfonyUX.twigComponent.preMountParameterType') + ->line($method->getLine()) + ->tip('Change the parameter type to "array".') ->build(); } } - // Check that there is exactly one parameter of type array - if (count($node->params) !== 1) { - $errors[] = RuleErrorBuilder::message( - sprintf('Method "%s" with #[PreMount] attribute must have exactly one parameter of type "array".', $node->name->toString()) - ) - ->identifier('symfonyUX.twigComponent.preMountMethodInvalidParameterCount') - ->line($node->getLine()) - ->tip('The method should have exactly one parameter: "array $data".') + // Check return type (must be array, void, or array|void) + $isValidReturnType = $methodReturnType->isVoid()->yes() + || $methodReturnType->isArray()->yes() + || ($methodReturnType->isArray()->maybe() && $methodReturnType->isVoid()->maybe()); + + if (! $isValidReturnType) { + $errors[] = RuleErrorBuilder::message(sprintf('Method "%s" with #[PreMount] attribute must have a return type of "array", "void", or "array|void".', $methodName)) + ->identifier('symfonyUX.twigComponent.preMountReturnType') + ->line($method->getLine()) + ->tip('Change the return type to ": array", ": void", or ": array|void".') ->build(); - } else { - $param = $node->params[0]; - $paramType = $param->type; - - if (! $paramType instanceof Node\Identifier || $paramType->toString() !== 'array') { - $errors[] = RuleErrorBuilder::message( - sprintf('Method "%s" with #[PreMount] attribute must have a parameter of type "array".', $node->name->toString()) - ) - ->identifier('symfonyUX.twigComponent.preMountMethodInvalidParameterType') - ->line($param->getLine()) - ->tip('Change the parameter type to "array".') - ->build(); - } } return $errors; diff --git a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/ClassNameShouldNotEndWithComponentRuleTest.php b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/ClassNameShouldNotEndWithComponentRuleTest.php index 52200fd..249fee2 100644 --- a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/ClassNameShouldNotEndWithComponentRuleTest.php +++ b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/ClassNameShouldNotEndWithComponentRuleTest.php @@ -16,7 +16,7 @@ final class ClassNameShouldNotEndWithComponentRuleTest extends RuleTestCase public function testViolations(): void { $this->analyse( - [__DIR__ . '/Fixture/InvalidComponentName.php'], + [__DIR__ . '/Fixture/AlertComponent.php'], [ [ 'Twig component class "AlertComponent" should not end with "Component".', @@ -27,7 +27,7 @@ public function testViolations(): void ); $this->analyse( - [__DIR__ . '/Fixture/InvalidLiveComponentName.php'], + [__DIR__ . '/Fixture/CounterComponent.php'], [ [ 'Twig component class "CounterComponent" should not end with "Component".', diff --git a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/InvalidComponentName.php b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/AlertComponent.php similarity index 100% rename from tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/InvalidComponentName.php rename to tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/AlertComponent.php diff --git a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/InvalidLiveComponentName.php b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/CounterComponent.php similarity index 100% rename from tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/InvalidLiveComponentName.php rename to tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/CounterComponent.php diff --git a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidComponentName.php b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidComponentName.php index 15428a5..f654774 100644 --- a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidComponentName.php +++ b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidComponentName.php @@ -7,6 +7,6 @@ use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; #[AsTwigComponent] -final class Alert +final class ValidComponentName { } diff --git a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidLiveComponentName.php b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidLiveComponentName.php index ec1a72f..d871198 100644 --- a/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidLiveComponentName.php +++ b/tests/Rules/TwigComponent/ClassNameShouldNotEndWithComponentRule/Fixture/ValidLiveComponentName.php @@ -7,6 +7,6 @@ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; #[AsLiveComponent] -final class Counter +final class ValidLiveComponentName { } diff --git a/tests/Rules/TwigComponent/ForbiddenAttributesPropertyRule/Fixture/ComponentWithCustomAttributesProperty.php b/tests/Rules/TwigComponent/ForbiddenAttributesPropertyRule/Fixture/ComponentWithCustomAttributesProperty.php index 8fc7fea..14b5665 100644 --- a/tests/Rules/TwigComponent/ForbiddenAttributesPropertyRule/Fixture/ComponentWithCustomAttributesProperty.php +++ b/tests/Rules/TwigComponent/ForbiddenAttributesPropertyRule/Fixture/ComponentWithCustomAttributesProperty.php @@ -7,7 +7,7 @@ use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; #[AsTwigComponent(attributesVar: 'customAttributes')] -final class ComponentWithAttributesProperty +final class ComponentWithCustomAttributesProperty { public string $customAttributes; } diff --git a/tests/Rules/TwigComponent/PostMountMethodSignatureRule/Fixture/InvalidLiveComponent.php b/tests/Rules/TwigComponent/PostMountMethodSignatureRule/Fixture/InvalidLiveComponent.php new file mode 100644 index 0000000..bf1f56b --- /dev/null +++ b/tests/Rules/TwigComponent/PostMountMethodSignatureRule/Fixture/InvalidLiveComponent.php @@ -0,0 +1,28 @@ + + */ +final class PostMountMethodSignatureRuleTest extends RuleTestCase +{ + public function testInvalidVisibility(): void + { + $this->analyse( + [__DIR__ . '/Fixture/InvalidVisibility.php'], + [ + [ + 'Method "postMountProtected" with #[PostMount] attribute must be public.', + 13, + 'Change the method visibility to public.', + ], + [ + 'Method "postMountPrivate" with #[PostMount] attribute must be public.', + 18, + 'Change the method visibility to public.', + ], + ] + ); + } + + public function testInvalidParameterCount(): void + { + $this->analyse( + [__DIR__ . '/Fixture/InvalidParameterCount.php'], + [ + [ + 'Method "postMountTooManyParams" with #[PostMount] attribute must have at most one parameter of type "array".', + 13, + 'The method should have zero or one parameter: "array $data" (optional).', + ], + ] + ); + } + + public function testInvalidParameterType(): void + { + $this->analyse( + [__DIR__ . '/Fixture/InvalidParameterType.php'], + [ + [ + 'Method "postMountWrongType" with #[PostMount] attribute must have a parameter of type "array".', + 13, + 'Change the parameter type to "array".', + ], + [ + 'Method "postMountIntType" with #[PostMount] attribute must have a parameter of type "array".', + 18, + 'Change the parameter type to "array".', + ], + ] + ); + } + + public function testInvalidReturnType(): void + { + $this->analyse( + [__DIR__ . '/Fixture/InvalidReturnType.php'], + [ + [ + 'Method "postMountStringReturn" with #[PostMount] attribute must have a return type of "array", "void", or "array|void".', + 13, + 'Change the return type to ": array", ": void", or ": array|void".', + ], + [ + 'Method "postMountIntReturn" with #[PostMount] attribute must have a return type of "array", "void", or "array|void".', + 19, + 'Change the return type to ": array", ": void", or ": array|void".', + ], + [ + 'Method "postMountBoolReturn" with #[PostMount] attribute must have a return type of "array", "void", or "array|void".', + 25, + 'Change the return type to ": array", ": void", or ": array|void".', + ], + ] + ); + } + + public function testInvalidLiveComponent(): void + { + $this->analyse( + [__DIR__ . '/Fixture/InvalidLiveComponent.php'], + [ + [ + 'Method "postMountWrongType" with #[PostMount] attribute must have a parameter of type "array".', + 13, + 'Change the parameter type to "array".', + ], + [ + 'Method "postMountWrongReturn" with #[PostMount] attribute must have a return type of "array", "void", or "array|void".', + 18, + 'Change the return type to ": array", ": void", or ": array|void".', + ], + [ + 'Method "postMountPrivate" with #[PostMount] attribute must be public.', + 24, + 'Change the method visibility to public.', + ], + ] + ); + } + + public function testNoViolations(): void + { + $this->analyse( + [__DIR__ . '/Fixture/NotAComponent.php'], + [] + ); + + $this->analyse( + [__DIR__ . '/Fixture/ValidTwigComponent.php'], + [] + ); + + $this->analyse( + [__DIR__ . '/Fixture/ValidLiveComponent.php'], + [] + ); + } + + public static function getAdditionalConfigFiles(): array + { + return [__DIR__ . '/config/configured_rule.neon']; + } + + protected function getRule(): Rule + { + return self::getContainer()->getByType(PostMountMethodSignatureRule::class); + } +} diff --git a/tests/Rules/TwigComponent/PostMountMethodSignatureRule/config/configured_rule.neon b/tests/Rules/TwigComponent/PostMountMethodSignatureRule/config/configured_rule.neon new file mode 100644 index 0000000..620095f --- /dev/null +++ b/tests/Rules/TwigComponent/PostMountMethodSignatureRule/config/configured_rule.neon @@ -0,0 +1,2 @@ +rules: + - Kocal\PHPStanSymfonyUX\Rules\TwigComponent\PostMountMethodSignatureRule diff --git a/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidLiveComponent.php b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidLiveComponent.php new file mode 100644 index 0000000..8576b7f --- /dev/null +++ b/tests/Rules/TwigComponent/PreMountMethodSignatureRule/Fixture/InvalidLiveComponent.php @@ -0,0 +1,28 @@ +analyse( - [__DIR__ . '/Fixture/InvalidNotPublic.php'], + [__DIR__ . '/Fixture/InvalidVisibility.php'], [ [ - 'Method "preMount" with #[PreMount] attribute must be public.', + 'Method "preMountProtected" with #[PreMount] attribute must be public.', 13, 'Change the method visibility to public.', ], - ] - ); - - $this->analyse( - [__DIR__ . '/Fixture/InvalidNoReturnType.php'], - [ [ - 'Method "preMount" with #[PreMount] attribute must have a return type of "array".', - 13, - 'Add ": array" return type to the method.', + 'Method "preMountPrivate" with #[PreMount] attribute must be public.', + 18, + 'Change the method visibility to public.', ], ] ); + } + public function testInvalidParameterCount(): void + { $this->analyse( - [__DIR__ . '/Fixture/InvalidWrongReturnType.php'], + [__DIR__ . '/Fixture/InvalidParameterCount.php'], [ [ - 'Method "preMount" with #[PreMount] attribute must have a return type of "array".', - 14, - 'Change the return type to ": array".', + 'Method "preMountTooManyParams" with #[PreMount] attribute must have at most one parameter of type "array".', + 13, + 'The method should have zero or one parameter: "array $data" (optional).', ], ] ); + } + public function testInvalidParameterType(): void + { $this->analyse( - [__DIR__ . '/Fixture/InvalidNoParameter.php'], + [__DIR__ . '/Fixture/InvalidParameterType.php'], [ [ - 'Method "preMount" with #[PreMount] attribute must have exactly one parameter of type "array".', + 'Method "preMountWrongType" with #[PreMount] attribute must have a parameter of type "array".', 13, - 'The method should have exactly one parameter: "array $data".', + 'Change the parameter type to "array".', + ], + [ + 'Method "preMountIntType" with #[PreMount] attribute must have a parameter of type "array".', + 18, + 'Change the parameter type to "array".', ], ] ); + } + public function testInvalidReturnType(): void + { $this->analyse( - [__DIR__ . '/Fixture/InvalidTooManyParameters.php'], + [__DIR__ . '/Fixture/InvalidReturnType.php'], [ [ - 'Method "preMount" with #[PreMount] attribute must have exactly one parameter of type "array".', + 'Method "preMountStringReturn" with #[PreMount] attribute must have a return type of "array", "void", or "array|void".', 13, - 'The method should have exactly one parameter: "array $data".', + 'Change the return type to ": array", ": void", or ": array|void".', + ], + [ + 'Method "preMountIntReturn" with #[PreMount] attribute must have a return type of "array", "void", or "array|void".', + 19, + 'Change the return type to ": array", ": void", or ": array|void".', ], - ] - ); - - $this->analyse( - [__DIR__ . '/Fixture/InvalidWithNullableReturnType.php'], - [ [ - 'Method "preMount" with #[PreMount] attribute must have a return type of "array".', - 14, - 'Change the return type to ": array".', + 'Method "preMountBoolReturn" with #[PreMount] attribute must have a return type of "array", "void", or "array|void".', + 25, + 'Change the return type to ": array", ": void", or ": array|void".', ], ] ); + } + public function testInvalidLiveComponent(): void + { $this->analyse( - [__DIR__ . '/Fixture/InvalidWrongParameterType.php'], + [__DIR__ . '/Fixture/InvalidLiveComponent.php'], [ [ - 'Method "preMount" with #[PreMount] attribute must have a parameter of type "array".', - 14, + 'Method "preMountWrongType" with #[PreMount] attribute must have a parameter of type "array".', + 13, 'Change the parameter type to "array".', ], + [ + 'Method "preMountWrongReturn" with #[PreMount] attribute must have a return type of "array", "void", or "array|void".', + 18, + 'Change the return type to ": array", ": void", or ": array|void".', + ], + [ + 'Method "preMountPrivate" with #[PreMount] attribute must be public.', + 24, + 'Change the method visibility to public.', + ], ] ); }