diff --git a/composer.json b/composer.json index 64dbab04fa..23df88ef8a 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,8 @@ }, "autoload-dev": { "psr-4": { - "tests\\": "tests/" + "tests\\": "tests/", + "EspoDev\\": "dev/" } }, "repositories": [ diff --git a/dev/PHPStan/Extensions/EntityManagerReturnType.php b/dev/PHPStan/Extensions/EntityManagerReturnType.php new file mode 100644 index 0000000000..ecd2ee4629 --- /dev/null +++ b/dev/PHPStan/Extensions/EntityManagerReturnType.php @@ -0,0 +1,154 @@ +getName(), $this->supportedMethodNameList); + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type { + + $methodName = $methodReflection->getName(); + + if ($methodName === 'getEntity') { + return $this->getGetEntity($methodReflection, $methodCall, $scope); + } + + if ($methodName === 'getRDBRepository') { + return $this->getGetRDBRepository($methodReflection, $methodCall, $scope); + } + + throw new RuntimeException("Not supported method."); + } + + private function getGetEntity( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type { + + $value = $methodCall->args[0]->value; + + if (!$value instanceof String_) { + return new UnionType([ + new ObjectType(Entity::class), + new NullType(), + ]); + } + + $entityType = $value->value; + + $className = $this->findEntityClassName($entityType) ?? Entity::class; + + return new UnionType([ + new ObjectType($className), + new NullType(), + ]); + } + + private function findEntityClassName(string $entityType): ?string + { + foreach ($this->entityNamespaceList as $namespace) { + $className = $namespace . '\\' . Util::normilizeClassName($entityType); + + if (class_exists($className)) { + return $className; + } + } + + return null; + } + + private function getGetRDBRepository( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type { + + $value = $methodCall->args[0]->value; + + if (!$value instanceof String_) { + return new ObjectType(RDBRepository::class); + } + + $entityType = $value->value; + + $entityClassName = $this->findEntityClassName($entityType); + + if ($entityClassName) { + return new GenericObjectType(RDBRepository::class, [new ObjectType($entityClassName)]); + } + + return new ObjectType(RDBRepository::class); + } +} diff --git a/phpstan.neon b/phpstan.neon index d13eed8ba6..ad7ef4d8aa 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,3 +6,8 @@ parameters: reportUnmatchedIgnoredErrors: false excludePaths: - application/Espo/Core/Select/SelectManager.php +services: + - + class: EspoDev\PHPStan\Extensions\EntityManagerReturnType + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension