From 45eb613a921003cd139a5a4893e4054ea21b5d50 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Sun, 28 Jan 2024 22:52:29 +0300 Subject: [PATCH 01/10] Initial commit of fork --- LICENSE | 38 ++++++++++--------- README.md | 4 +- composer.json | 11 +++--- extension.neon | 14 +++---- phpunit.xml | 2 +- src/ClassComponentsExtension.php | 2 +- src/ClassModelsExtension.php | 2 +- src/ClassPropertiesExtension.php | 5 +-- src/ClassReflectionFinder.php | 2 +- src/ClassRegistryInitExtension.php | 6 ++- src/ClassTasksExtension.php | 2 +- ...omponentOnFlyMethodReturnTypeExtension.php | 2 +- src/ModelBehaviorMethodExtractor.php | 7 +--- src/ModelBehaviorMethodWrapper.php | 7 +--- src/ModelBehaviorsExtension.php | 14 +++---- src/PublicReadOnlyPropertyReflection.php | 14 ++----- src/Service/SchemaService.php | 6 ++- stubs/{Utility.php => Utility.stub} | 0 tests/Feature/ClassRegistryInitTest.php | 4 +- tests/Feature/ComponentExtensionsTest.php | 4 +- tests/Feature/ControllerExtensionsTest.php | 4 +- ...nentOnFlyMethodReturnTypeExtensionTest.php | 2 +- tests/Feature/ModelExtensionsTest.php | 4 +- tests/Feature/ShellExtensionsTest.php | 4 +- 24 files changed, 81 insertions(+), 79 deletions(-) rename stubs/{Utility.php => Utility.stub} (100%) diff --git a/LICENSE b/LICENSE index d36a04b..c41d93e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,25 @@ -MIT License +The MIT License +--------------- -Copyright (c) 2022 Andrew Riddlestone +Copyright (c) 2023 Oleg Zhulnev (https://github.com/sidz) -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 249667f..9eba9c5 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,14 @@ PHPStan extensions to help test CakePHP 2 projects with PHPStan Installation is best done through composer: ```shell -composer require --dev ariddlestone/phpstan-cakephp2 +composer require --dev sidz/phpstan-cakephp2 ``` You will need to make sure the extension is included in your phpstan config: ```yaml # phpstan.neon includes: - - vendor/ariddlestone/phpstan-cakephp2/extension.neon + - vendor/sidz/phpstan-cakephp2/extension.neon ``` If you have behavior classes in odd locations (perhaps in a vendor directory) you will need to add those locations to diff --git a/composer.json b/composer.json index 1d3c7b1..c472670 100644 --- a/composer.json +++ b/composer.json @@ -1,12 +1,12 @@ { - "name": "ariddlestone/phpstan-cakephp2", + "name": "sidz/phpstan-cakephp2", "description": "An extension to help test CakePHP 2 projects with PHPStan", "type": "library", "license": "MIT", "authors": [ { - "name": "Andrew Riddlestone", - "email": "andrew.riddlestone@gmail.com" + "name": "Oleg Zhulnev", + "email": "plbsid@gmail.com" } ], "require": { @@ -21,12 +21,12 @@ }, "autoload": { "psr-4": { - "ARiddlestone\\PHPStanCakePHP2\\": "src/" + "PHPStanCakePHP2\\": "src/" } }, "autoload-dev": { "psr-4": { - "ARiddlestone\\PHPStanCakePHP2\\Test\\": "tests/" + "PHPStanCakePHP2\\Test\\": "tests/" }, "classmap": [ "tests/Feature/classes", @@ -42,7 +42,6 @@ ] }, "scripts": { - "extract-phpstan": "phar extract -f vendor/phpstan/phpstan/phpstan.phar phpstan", "phpinsights": "phpinsights analyse --no-interaction --ansi --config-path=phpinsights.php --summary src", "phpinsights-github": "phpinsights analyse --no-interaction --ansi --config-path=phpinsights.php --format=github-action src", "phpstan": "phpstan", diff --git a/extension.neon b/extension.neon index b1cc782..15c699c 100644 --- a/extension.neon +++ b/extension.neon @@ -11,27 +11,27 @@ parameters: stubFiles: - stubs/Utility.php services: - - class: ARiddlestone\PHPStanCakePHP2\ClassComponentsExtension + - class: PHPStanCakePHP2\ClassComponentsExtension tags: - phpstan.broker.propertiesClassReflectionExtension - - class: ARiddlestone\PHPStanCakePHP2\ClassModelsExtension + - class: PHPStanCakePHP2\ClassModelsExtension tags: - phpstan.broker.propertiesClassReflectionExtension - - class: ARiddlestone\PHPStanCakePHP2\ClassRegistryInitExtension + - class: PHPStanCakePHP2\ClassRegistryInitExtension tags: - phpstan.broker.dynamicStaticMethodReturnTypeExtension - - class: ARiddlestone\PHPStanCakePHP2\ClassTasksExtension + - class: PHPStanCakePHP2\ClassTasksExtension tags: - phpstan.broker.propertiesClassReflectionExtension - - class: ARiddlestone\PHPStanCakePHP2\ModelBehaviorsExtension + - class: PHPStanCakePHP2\ModelBehaviorsExtension arguments: behaviorPaths: %ModelBehaviorsExtension.behaviorPaths% tags: - phpstan.broker.methodsClassReflectionExtension - - class: ARiddlestone\PHPStanCakePHP2\Service\SchemaService + - class: PHPStanCakePHP2\Service\SchemaService arguments: schemaPaths: %SchemaService.schemaPaths% - - class: ARiddlestone\PHPStanCakePHP2\LoadComponentOnFlyMethodReturnTypeExtension + - class: PHPStanCakePHP2\LoadComponentOnFlyMethodReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension parametersSchema: diff --git a/phpunit.xml b/phpunit.xml index 9993376..9b8d058 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,6 @@ */ - private $behaviorPaths; + private array $behaviorPaths; /** * @var array|null */ - private $behaviorMethods = null; + private ?array $behaviorMethods = null; /** * @param array $behaviorPaths @@ -54,7 +51,8 @@ public function hasMethod( array_map( [$this, 'getMethodReflectionName'], $this->getBehaviorMethods() - ) + ), + true ); } diff --git a/src/PublicReadOnlyPropertyReflection.php b/src/PublicReadOnlyPropertyReflection.php index a912fa6..a0818ae 100644 --- a/src/PublicReadOnlyPropertyReflection.php +++ b/src/PublicReadOnlyPropertyReflection.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace ARiddlestone\PHPStanCakePHP2; +namespace PHPStanCakePHP2; use PHPStan\Reflection\ClassReflection; use PHPStan\Reflection\PropertyReflection; @@ -12,15 +12,9 @@ final class PublicReadOnlyPropertyReflection implements PropertyReflection { - /** - * @var string - */ - private $name; - - /** - * @var ClassReflection - */ - private $declaringClass; + private string $name; + + private ClassReflection $declaringClass; public function __construct(string $name, ClassReflection $declaringClass) { diff --git a/src/Service/SchemaService.php b/src/Service/SchemaService.php index f9890aa..f296807 100644 --- a/src/Service/SchemaService.php +++ b/src/Service/SchemaService.php @@ -1,8 +1,10 @@ Date: Sun, 28 Jan 2024 23:21:41 +0300 Subject: [PATCH 02/10] fix stub filename --- extension.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension.neon b/extension.neon index 15c699c..602d91b 100644 --- a/extension.neon +++ b/extension.neon @@ -9,7 +9,7 @@ parameters: schemaPaths: - app/Config/Schema/*.php stubFiles: - - stubs/Utility.php + - stubs/Utility.stub services: - class: PHPStanCakePHP2\ClassComponentsExtension tags: From 1613b9fac93152978c6c93d68cc5779ab31096f5 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Sun, 28 Jan 2024 23:04:11 +0300 Subject: [PATCH 03/10] Fix ClassRegistryInit doesn't work with ClassConstFetch AST --- src/ClassRegistryInitExtension.php | 12 ++++++++++-- tests/Feature/data/class_registry_init.php | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ClassRegistryInitExtension.php b/src/ClassRegistryInitExtension.php index 6b4ec15..608671c 100644 --- a/src/ClassRegistryInitExtension.php +++ b/src/ClassRegistryInitExtension.php @@ -4,6 +4,8 @@ namespace PHPStanCakePHP2; +use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Name; use PHPStanCakePHP2\Service\SchemaService; use Inflector; use PhpParser\ConstExprEvaluator; @@ -44,9 +46,15 @@ public function isStaticMethodSupported(MethodReflection $methodReflection): boo public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): ?Type { - $arg1 = $methodCall->getArgs()[0]->value; + $value = $methodCall->getArgs()[0]->value; $evaluator = new ConstExprEvaluator(); - $arg1 = $evaluator->evaluateSilently($arg1); + + if ($value instanceof ClassConstFetch && $value->class instanceof Name) { + $value = $value->class->toString(); + } + + $arg1 = $evaluator->evaluateSilently($value); + if (! is_string($arg1)) { return $this->getDefaultType(); } diff --git a/tests/Feature/data/class_registry_init.php b/tests/Feature/data/class_registry_init.php index 90b0776..2580723 100644 --- a/tests/Feature/data/class_registry_init.php +++ b/tests/Feature/data/class_registry_init.php @@ -12,3 +12,6 @@ $modelWithoutClass = ClassRegistry::init('TableWithoutModel'); assertType('Model', $modelWithoutClass); + +$class = ClassRegistry::init(BasicModel::class); +assertType('BasicModel', $class); From 3f895981ff0ab0966d1acc3fd6c7416d7c568d08 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Sun, 28 Jan 2024 23:19:44 +0300 Subject: [PATCH 04/10] Fix ClassRegistryInit doesn't work with ClassConstFetch AST --- src/ClassRegistryInitExtension.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ClassRegistryInitExtension.php b/src/ClassRegistryInitExtension.php index 608671c..184a660 100644 --- a/src/ClassRegistryInitExtension.php +++ b/src/ClassRegistryInitExtension.php @@ -6,6 +6,7 @@ use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Name; +use PhpParser\Node\Scalar\String_; use PHPStanCakePHP2\Service\SchemaService; use Inflector; use PhpParser\ConstExprEvaluator; @@ -49,8 +50,8 @@ public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, $value = $methodCall->getArgs()[0]->value; $evaluator = new ConstExprEvaluator(); - if ($value instanceof ClassConstFetch && $value->class instanceof Name) { - $value = $value->class->toString(); + if ($value instanceof ClassConstFetch && $value->class instanceof Name\FullyQualified) { + $value = new String_($value->class->toString()); } $arg1 = $evaluator->evaluateSilently($value); From 8121dde487f522160668359264e478a72adc2f8c Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Mon, 29 Jan 2024 17:21:51 +0300 Subject: [PATCH 05/10] Mark as Default type if variable is passed into `ClassRegistr::init` method --- src/ClassRegistryInitExtension.php | 11 +++++++++-- tests/Feature/data/class_registry_init.php | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ClassRegistryInitExtension.php b/src/ClassRegistryInitExtension.php index 184a660..409623f 100644 --- a/src/ClassRegistryInitExtension.php +++ b/src/ClassRegistryInitExtension.php @@ -5,6 +5,7 @@ namespace PHPStanCakePHP2; use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; use PhpParser\Node\Scalar\String_; use PHPStanCakePHP2\Service\SchemaService; @@ -48,23 +49,29 @@ public function isStaticMethodSupported(MethodReflection $methodReflection): boo public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): ?Type { $value = $methodCall->getArgs()[0]->value; - $evaluator = new ConstExprEvaluator(); + + if ($value instanceof Variable) { + return new ObjectType('Model'); + } if ($value instanceof ClassConstFetch && $value->class instanceof Name\FullyQualified) { $value = new String_($value->class->toString()); } - $arg1 = $evaluator->evaluateSilently($value); + $arg1 = (new ConstExprEvaluator())->evaluateSilently($value); if (! is_string($arg1)) { return $this->getDefaultType(); } + if ($this->reflectionProvider->hasClass($arg1)) { return new ObjectType($arg1); } + if ($this->schemaService->hasTable(Inflector::tableize($arg1))) { return new ObjectType('Model'); } + return $this->getDefaultType(); } diff --git a/tests/Feature/data/class_registry_init.php b/tests/Feature/data/class_registry_init.php index 2580723..54dcd20 100644 --- a/tests/Feature/data/class_registry_init.php +++ b/tests/Feature/data/class_registry_init.php @@ -15,3 +15,7 @@ $class = ClassRegistry::init(BasicModel::class); assertType('BasicModel', $class); + +$var = 'BasicModel'; + +assertType('Model', ClassRegistry::init($var)); From e8a3efe90d7d6c4a4eb8f357ec5a3818717e94d6 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Mon, 29 Jan 2024 18:13:07 +0300 Subject: [PATCH 06/10] Fix error occurred when not a string is passed into `ClassRegistry::init` method --- src/ClassRegistryInitExtension.php | 26 +++++++++------------- tests/Feature/data/class_registry_init.php | 4 +++- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/ClassRegistryInitExtension.php b/src/ClassRegistryInitExtension.php index 409623f..97cbe8e 100644 --- a/src/ClassRegistryInitExtension.php +++ b/src/ClassRegistryInitExtension.php @@ -4,10 +4,12 @@ namespace PHPStanCakePHP2; +use PhpParser\Node\Expr; use PhpParser\Node\Expr\ClassConstFetch; use PhpParser\Node\Expr\Variable; use PhpParser\Node\Name; use PhpParser\Node\Scalar\String_; +use PHPStan\Type\Constant\ConstantStringType; use PHPStanCakePHP2\Service\SchemaService; use Inflector; use PhpParser\ConstExprEvaluator; @@ -48,27 +50,19 @@ public function isStaticMethodSupported(MethodReflection $methodReflection): boo public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, Scope $scope): ?Type { - $value = $methodCall->getArgs()[0]->value; + $argumentType = $scope->getType($methodCall->getArgs()[0]->value); - if ($value instanceof Variable) { - return new ObjectType('Model'); - } - - if ($value instanceof ClassConstFetch && $value->class instanceof Name\FullyQualified) { - $value = new String_($value->class->toString()); - } - - $arg1 = (new ConstExprEvaluator())->evaluateSilently($value); - - if (! is_string($arg1)) { + if (!$argumentType instanceof ConstantStringType) { return $this->getDefaultType(); } - if ($this->reflectionProvider->hasClass($arg1)) { - return new ObjectType($arg1); + $value = $argumentType->getValue(); + + if ($this->reflectionProvider->hasClass($value)) { + return new ObjectType($value); } - if ($this->schemaService->hasTable(Inflector::tableize($arg1))) { + if ($this->schemaService->hasTable(Inflector::tableize($value))) { return new ObjectType('Model'); } @@ -79,7 +73,7 @@ private function getDefaultType(): Type { return new UnionType([ new BooleanType(), - new ObjectWithoutClassType() + new ObjectWithoutClassType(), ]); } } diff --git a/tests/Feature/data/class_registry_init.php b/tests/Feature/data/class_registry_init.php index 54dcd20..57ca51c 100644 --- a/tests/Feature/data/class_registry_init.php +++ b/tests/Feature/data/class_registry_init.php @@ -18,4 +18,6 @@ $var = 'BasicModel'; -assertType('Model', ClassRegistry::init($var)); +assertType('BasicModel', ClassRegistry::init($var)); + +assertType('bool|object', ClassRegistry::init([123])); From 30f04ce2311663732ec47e05146bef94478cd104 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Sun, 24 Dec 2023 21:37:25 +0300 Subject: [PATCH 07/10] Teach see a difference between Component and Model especially when both have methods with the same name --- src/ClassComponentsExtension.php | 92 +++++++++++++++++-- tests/Feature/ControllerExtensionsTest.php | 2 + .../classes/Controller/BaseController.php | 11 +++ .../classes/Controller/BasicController.php | 8 +- .../Controller/Component/BasicComponent.php | 8 +- .../Component/SameAsModelComponent.php | 9 ++ .../Controller/SameAsModelController.php | 12 +++ tests/Feature/classes/Model/SameAsModel.php | 9 ++ ...oller_component_from_parent_controller.php | 10 ++ ...mponent_with_same_method_name_as_model.php | 15 +++ 10 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 tests/Feature/classes/Controller/BaseController.php create mode 100644 tests/Feature/classes/Controller/Component/SameAsModelComponent.php create mode 100644 tests/Feature/classes/Controller/SameAsModelController.php create mode 100644 tests/Feature/classes/Model/SameAsModel.php create mode 100644 tests/Feature/data/existing_controller_component_from_parent_controller.php create mode 100644 tests/Feature/data/existing_controller_component_with_same_method_name_as_model.php diff --git a/src/ClassComponentsExtension.php b/src/ClassComponentsExtension.php index 689d227..bc0bfa5 100644 --- a/src/ClassComponentsExtension.php +++ b/src/ClassComponentsExtension.php @@ -4,17 +4,58 @@ namespace PHPStanCakePHP2; -final class ClassComponentsExtension extends ClassPropertiesExtension +use PhpParser\Node\Expr\Array_; +use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Name\FullyQualified; +use PhpParser\Node\Scalar\String_; +use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\PropertiesClassReflectionExtension; +use PHPStan\Reflection\PropertyReflection; +use PHPStan\Reflection\ReflectionProvider; + +final class ClassComponentsExtension implements PropertiesClassReflectionExtension { - protected function getPropertyParentClassName(): string + private ReflectionProvider $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) { - return 'Component'; + $this->reflectionProvider = $reflectionProvider; + } + + public function hasProperty(ClassReflection $classReflection, string $propertyName): bool + { + if (!array_filter($this->getContainingClassNames(), [$classReflection, 'is'])) { + return false; + } + + $isDefinedInComponentsProperty = (bool) array_filter( + $this->getDefinedComponentsAsList($classReflection), + static fn (string $componentName): bool => $componentName === $propertyName + ); + + if (!$isDefinedInComponentsProperty) { + return false; + } + + $propertyClassName = $this->getClassNameFromPropertyName($propertyName); + + return $this->reflectionProvider->hasClass($propertyClassName) + && $this->reflectionProvider->getClass($propertyClassName) + ->is('Component'); + } + + public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + { + return new PublicReadOnlyPropertyReflection( + $this->getClassNameFromPropertyName($propertyName), + $classReflection + ); } /** * @return array */ - protected function getContainingClassNames(): array + private function getContainingClassNames(): array { return [ 'Controller', @@ -22,9 +63,44 @@ protected function getContainingClassNames(): array ]; } - protected function getClassNameFromPropertyName( - string $propertyName - ): string { - return $propertyName . 'Component'; + private function getClassNameFromPropertyName(string $propertyName): string + { + return str_contains($propertyName, 'Component') ? $propertyName : $propertyName . 'Component'; + } + + /** + * @return list + */ + private function getDefinedComponentsAsList(ClassReflection $classReflection): array + { + $definedComponents = []; + + foreach (array_merge([$classReflection], $classReflection->getParents()) as $class) { + if (!$class->hasProperty('components')) { + continue; + } + + $defaultValue = $class->getNativeProperty('components') + ->getNativeReflection() + ->getDefaultValueExpression(); + + if (!$defaultValue instanceof Array_) { + continue; + } + + foreach ($defaultValue->items as $item) { + if ($item->value instanceof String_) { + $definedComponents[] = $item->value->value; + + continue; + } + + if ($item->value instanceof ClassConstFetch && $item->value->class instanceof FullyQualified) { + $definedComponents[] = $item->value->class->toString(); + } + } + } + + return $definedComponents; } } diff --git a/tests/Feature/ControllerExtensionsTest.php b/tests/Feature/ControllerExtensionsTest.php index 7be96c5..5207719 100644 --- a/tests/Feature/ControllerExtensionsTest.php +++ b/tests/Feature/ControllerExtensionsTest.php @@ -16,6 +16,8 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/existing_controller_model.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/existing_controller_component.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/invalid_controller_property.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/existing_controller_component_with_same_method_name_as_model.php'); + yield from $this->gatherAssertTypes(__DIR__ . '/data/existing_controller_component_from_parent_controller.php'); } /** diff --git a/tests/Feature/classes/Controller/BaseController.php b/tests/Feature/classes/Controller/BaseController.php new file mode 100644 index 0000000..692ec43 --- /dev/null +++ b/tests/Feature/classes/Controller/BaseController.php @@ -0,0 +1,11 @@ + + */ + public $components = ['Basic']; +} diff --git a/tests/Feature/classes/Controller/BasicController.php b/tests/Feature/classes/Controller/BasicController.php index 62c9338..c0318a0 100644 --- a/tests/Feature/classes/Controller/BasicController.php +++ b/tests/Feature/classes/Controller/BasicController.php @@ -1,3 +1,9 @@ + */ + public $components = ['Basic']; +} diff --git a/tests/Feature/classes/Controller/Component/BasicComponent.php b/tests/Feature/classes/Controller/Component/BasicComponent.php index 5d66fa7..64a5018 100644 --- a/tests/Feature/classes/Controller/Component/BasicComponent.php +++ b/tests/Feature/classes/Controller/Component/BasicComponent.php @@ -1,3 +1,9 @@ + */ + public $components = ['Second']; +} diff --git a/tests/Feature/classes/Controller/Component/SameAsModelComponent.php b/tests/Feature/classes/Controller/Component/SameAsModelComponent.php new file mode 100644 index 0000000..3eb6bde --- /dev/null +++ b/tests/Feature/classes/Controller/Component/SameAsModelComponent.php @@ -0,0 +1,9 @@ + + */ + public $components = [ + 'SameAsModel', + BasicComponent::class, + ]; +} diff --git a/tests/Feature/classes/Model/SameAsModel.php b/tests/Feature/classes/Model/SameAsModel.php new file mode 100644 index 0000000..8f377c8 --- /dev/null +++ b/tests/Feature/classes/Model/SameAsModel.php @@ -0,0 +1,9 @@ +Basic; + +assertType('BasicComponent', $component); diff --git a/tests/Feature/data/existing_controller_component_with_same_method_name_as_model.php b/tests/Feature/data/existing_controller_component_with_same_method_name_as_model.php new file mode 100644 index 0000000..d5c8ec3 --- /dev/null +++ b/tests/Feature/data/existing_controller_component_with_same_method_name_as_model.php @@ -0,0 +1,15 @@ +SameAsModel->sameMethod(); + +assertType('int', $component); + +/** @var SameAsModelController $controller */ +$component = $controller->BasicComponent; + +assertType('BasicComponent', $component); From 66db9e8761557c45cb813f249e51aa779d651f28 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Tue, 30 Jan 2024 00:11:25 +0300 Subject: [PATCH 08/10] Add Router.stub and allow to accept string as $url argument --- extension.neon | 1 + stubs/Routing/Router.stub | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 stubs/Routing/Router.stub diff --git a/extension.neon b/extension.neon index 602d91b..eb15a24 100644 --- a/extension.neon +++ b/extension.neon @@ -9,6 +9,7 @@ parameters: schemaPaths: - app/Config/Schema/*.php stubFiles: + - stubs/Routing/Router.stub - stubs/Utility.stub services: - class: PHPStanCakePHP2\ClassComponentsExtension diff --git a/stubs/Routing/Router.stub b/stubs/Routing/Router.stub new file mode 100644 index 0000000..36250c0 --- /dev/null +++ b/stubs/Routing/Router.stub @@ -0,0 +1,9 @@ + Date: Mon, 29 Apr 2024 21:31:02 +0300 Subject: [PATCH 09/10] Add Model.stub and define what find('count') returns --- extension.neon | 1 + stubs/Model/Model.stub | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 stubs/Model/Model.stub diff --git a/extension.neon b/extension.neon index eb15a24..ba06365 100644 --- a/extension.neon +++ b/extension.neon @@ -9,6 +9,7 @@ parameters: schemaPaths: - app/Config/Schema/*.php stubFiles: + - stubs/Model/Model.stub - stubs/Routing/Router.stub - stubs/Utility.stub services: diff --git a/stubs/Model/Model.stub b/stubs/Model/Model.stub new file mode 100644 index 0000000..37fb7bb --- /dev/null +++ b/stubs/Model/Model.stub @@ -0,0 +1,12 @@ + $query + * + * @return ($type is 'count' ? int : (array|int|null)) + */ + public function find($type = 'first', $query = array()) {} +} From 05001cf3836c08ae74e6671fa32912af8490b546 Mon Sep 17 00:00:00 2001 From: Oleg Zhulnev Date: Mon, 29 Apr 2024 21:47:56 +0300 Subject: [PATCH 10/10] Rename Utility.stub to ClassRegistry.stub and move to right namespace --- extension.neon | 2 +- stubs/{Utility.stub => Utility/ClassRegistry.stub} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename stubs/{Utility.stub => Utility/ClassRegistry.stub} (100%) diff --git a/extension.neon b/extension.neon index ba06365..1b1e7ee 100644 --- a/extension.neon +++ b/extension.neon @@ -11,7 +11,7 @@ parameters: stubFiles: - stubs/Model/Model.stub - stubs/Routing/Router.stub - - stubs/Utility.stub + - stubs/Utility/ClassRegistry.stub services: - class: PHPStanCakePHP2\ClassComponentsExtension tags: diff --git a/stubs/Utility.stub b/stubs/Utility/ClassRegistry.stub similarity index 100% rename from stubs/Utility.stub rename to stubs/Utility/ClassRegistry.stub