diff --git a/extension.neon b/extension.neon index 21e8e248..f85ff22c 100644 --- a/extension.neon +++ b/extension.neon @@ -1,6 +1,18 @@ parameters: doctrine: - repositoryClass: Doctrine\ORM\EntityRepository + odm: + mongodb: + registryClass: Doctrine\Bundle\MongoDBBundle\ManagerRegistry + managerClass: Doctrine\ODM\MongoDB\DocumentManager + repositoryClass: Doctrine\ODM\MongoDB\DocumentRepository + orm: + registryClass: Doctrine\Bundle\DoctrineBundle\Registry + managerClass: Doctrine\ORM\EntityManagerInterface + repositoryClass: Doctrine\ORM\EntityRepository + persistence: + registryClass: Doctrine\Common\Persistence\ManagerRegistry + managerClass: Doctrine\Common\Persistence\ObjectManager + repositoryClass: Doctrine\Common\Persistence\ObjectRepository services: - @@ -11,21 +23,82 @@ services: class: PHPStan\Type\Doctrine\DoctrineSelectableDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension + + - + class: PHPStan\Type\Doctrine\ObjectManagerFindDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Doctrine\ObjectManagerMergeDynamicReturnTypeExtension + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\EntityManagerFindDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectRepositoryDynamicReturnTypeExtension tags: - phpstan.broker.dynamicMethodReturnTypeExtension + - - class: PHPStan\Type\Doctrine\EntityManagerGetRepositoryDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension arguments: - repositoryClass: %doctrine.repositoryClass% + managerClass: %doctrine.persistence.managerClass% + repositoryClass: %doctrine.persistence.repositoryClass% tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\ObjectManagerMergeDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension + arguments: + managerClass: %doctrine.odm.mongodb.managerClass% + repositoryClass: %doctrine.odm.mongodb.repositoryClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Doctrine\ObjectManagerGetRepositoryDynamicReturnTypeExtension + arguments: + managerClass: %doctrine.orm.managerClass% + repositoryClass: %doctrine.orm.repositoryClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + + - + class: PHPStan\Type\Doctrine\ManagerRegistryGetManagerDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.persistence.registryClass% + managerClass: %doctrine.persistence.managerClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Doctrine\ManagerRegistryGetManagerDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.odm.mongodb.registryClass% + managerClass: %doctrine.odm.mongodb.managerClass% tags: - phpstan.broker.dynamicMethodReturnTypeExtension - - class: PHPStan\Type\Doctrine\EntityRepositoryDynamicReturnTypeExtension + class: PHPStan\Type\Doctrine\ManagerRegistryGetManagerDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.orm.registryClass% + managerClass: %doctrine.orm.managerClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + + - + class: PHPStan\Type\Doctrine\ManagerRegistryGetRepositoryDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.persistence.registryClass% + repositoryClass: %doctrine.persistence.repositoryClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Doctrine\ManagerRegistryGetRepositoryDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.odm.mongodb.registryClass% + repositoryClass: %doctrine.odm.mongodb.repositoryClass% + tags: + - phpstan.broker.dynamicMethodReturnTypeExtension + - + class: PHPStan\Type\Doctrine\ManagerRegistryGetRepositoryDynamicReturnTypeExtension + arguments: + registryClass: %doctrine.orm.registryClass% + repositoryClass: %doctrine.orm.repositoryClass% tags: - phpstan.broker.dynamicMethodReturnTypeExtension diff --git a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php b/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php index 2498cc8d..ed5bd0d1 100644 --- a/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/EntityManagerFindDynamicReturnTypeExtension.php @@ -2,53 +2,22 @@ namespace PHPStan\Type\Doctrine; -use PhpParser\Node\Expr\MethodCall; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\MethodReflection; -use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\MixedType; -use PHPStan\Type\ObjectType; -use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; +use const E_USER_DEPRECATED; +use function trigger_error; -class EntityManagerFindDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class EntityManagerFindDynamicReturnTypeExtension extends ObjectManagerFindDynamicReturnTypeExtension { - public function getClass(): string + public function __construct() { - return 'Doctrine\Common\Persistence\ObjectManager'; - } - - public function isMethodSupported(MethodReflection $methodReflection): bool - { - return in_array($methodReflection->getName(), [ - 'find', - 'getReference', - 'getPartialReference', - ], true); - } - - public function getTypeFromMethodCall( - MethodReflection $methodReflection, - MethodCall $methodCall, - Scope $scope - ): Type - { - $mixedType = new MixedType(); - if (count($methodCall->args) === 0) { - return $mixedType; - } - $argType = $scope->getType($methodCall->args[0]->value); - if (!$argType instanceof ConstantStringType) { - return $mixedType; - } - - $type = new ObjectType($argType->getValue()); - if ($methodReflection->getName() === 'find') { - $type = TypeCombinator::addNull($type); - } - - return $type; + @trigger_error( + sprintf( + 'Class %s is deprecated and will be removed. Use %s instead', + self::class, + ObjectManagerFindDynamicReturnTypeExtension::class + ), + E_USER_DEPRECATED + ); } } diff --git a/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php index b383c18f..5c599f56 100644 --- a/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/EntityManagerGetRepositoryDynamicReturnTypeExtension.php @@ -2,52 +2,24 @@ namespace PHPStan\Type\Doctrine; -use PhpParser\Node\Expr\MethodCall; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\MethodReflection; -use PHPStan\Reflection\ParametersAcceptorSelector; -use PHPStan\Type\Constant\ConstantStringType; -use PHPStan\Type\MixedType; -use PHPStan\Type\Type; +use const E_USER_DEPRECATED; +use function trigger_error; -class EntityManagerGetRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class EntityManagerGetRepositoryDynamicReturnTypeExtension extends ObjectManagerGetRepositoryDynamicReturnTypeExtension { - /** @var string */ - private $repositoryClass; - public function __construct(string $repositoryClass) { - $this->repositoryClass = $repositoryClass; - } - - public function getClass(): string - { - return 'Doctrine\Common\Persistence\ObjectManager'; - } - - public function isMethodSupported(MethodReflection $methodReflection): bool - { - return $methodReflection->getName() === 'getRepository'; - } - - public function getTypeFromMethodCall( - MethodReflection $methodReflection, - MethodCall $methodCall, - Scope $scope - ): Type - { - if (count($methodCall->args) === 0) { - return ParametersAcceptorSelector::selectSingle( - $methodReflection->getVariants() - )->getReturnType(); - } - $argType = $scope->getType($methodCall->args[0]->value); - if (!$argType instanceof ConstantStringType) { - return new MixedType(); - } - - return new EntityRepositoryType($argType->getValue(), $this->repositoryClass); + @trigger_error( + sprintf( + 'Class %s is deprecated and will be removed. Use %s instead', + self::class, + ObjectManagerGetRepositoryDynamicReturnTypeExtension::class + ), + E_USER_DEPRECATED + ); + + parent::__construct('Doctrine\Common\Persistence\ObjectManager', $repositoryClass); } } diff --git a/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php index b542508c..2fb38f43 100644 --- a/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php +++ b/src/Type/Doctrine/EntityRepositoryDynamicReturnTypeExtension.php @@ -2,51 +2,22 @@ namespace PHPStan\Type\Doctrine; -use PhpParser\Node\Expr\MethodCall; -use PHPStan\Analyser\Scope; -use PHPStan\Reflection\MethodReflection; -use PHPStan\Type\ArrayType; -use PHPStan\Type\IntegerType; -use PHPStan\Type\MixedType; -use PHPStan\Type\ObjectType; -use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; +use const E_USER_DEPRECATED; +use function trigger_error; -class EntityRepositoryDynamicReturnTypeExtension implements \PHPStan\Type\DynamicMethodReturnTypeExtension +class EntityRepositoryDynamicReturnTypeExtension extends ObjectRepositoryDynamicReturnTypeExtension { - public function getClass(): string + public function __construct() { - return 'Doctrine\ORM\EntityRepository'; - } - - public function isMethodSupported(MethodReflection $methodReflection): bool - { - $methodName = $methodReflection->getName(); - return strpos($methodName, 'findBy') === 0 - || strpos($methodName, 'findOneBy') === 0 - || $methodName === 'findAll' - || $methodName === 'find'; - } - - public function getTypeFromMethodCall( - MethodReflection $methodReflection, - MethodCall $methodCall, - Scope $scope - ): Type - { - $calledOnType = $scope->getType($methodCall->var); - if (!$calledOnType instanceof EntityRepositoryType) { - return new MixedType(); - } - $methodName = $methodReflection->getName(); - $entityType = new ObjectType($calledOnType->getEntityClass()); - - if ($methodName === 'find' || strpos($methodName, 'findOneBy') === 0) { - return TypeCombinator::addNull($entityType); - } - - return new ArrayType(new IntegerType(), $entityType); + @trigger_error( + sprintf( + 'Class %s is deprecated and will be removed. Use %s instead', + self::class, + ObjectRepositoryDynamicReturnTypeExtension::class + ), + E_USER_DEPRECATED + ); } } diff --git a/src/Type/Doctrine/EntityRepositoryType.php b/src/Type/Doctrine/EntityRepositoryType.php index 49c8c510..0b1b0845 100644 --- a/src/Type/Doctrine/EntityRepositoryType.php +++ b/src/Type/Doctrine/EntityRepositoryType.php @@ -2,29 +2,24 @@ namespace PHPStan\Type\Doctrine; -use PHPStan\Type\ObjectType; -use PHPStan\Type\VerbosityLevel; +use const E_USER_DEPRECATED; +use function trigger_error; -class EntityRepositoryType extends ObjectType +class EntityRepositoryType extends ObjectRepositoryType { - /** @var string */ - private $entityClass; - public function __construct(string $entityClass, string $repositoryClass) { - parent::__construct($repositoryClass); - $this->entityClass = $entityClass; - } - - public function getEntityClass(): string - { - return $this->entityClass; - } - - public function describe(VerbosityLevel $level): string - { - return sprintf('%s<%s>', parent::describe($level), $this->entityClass); + @trigger_error( + sprintf( + 'Class %s is deprecated and will be removed. Use %s instead', + self::class, + ObjectRepositoryType::class + ), + E_USER_DEPRECATED + ); + + parent::__construct($entityClass, $repositoryClass); } } diff --git a/src/Type/Doctrine/ManagerRegistryGetManagerDynamicReturnTypeExtension.php b/src/Type/Doctrine/ManagerRegistryGetManagerDynamicReturnTypeExtension.php new file mode 100644 index 00000000..ff78c069 --- /dev/null +++ b/src/Type/Doctrine/ManagerRegistryGetManagerDynamicReturnTypeExtension.php @@ -0,0 +1,63 @@ +registryClass = $registryClass; + $this->managerClass = $managerClass; + } + + public function getClass(): string + { + return $this->registryClass; + } + + public function isMethodSupported(MethodReflection $methodReflection): bool + { + return in_array($methodReflection->getName(), [ + 'getManager', + 'getManagers', + 'resetManager', + 'getManagerForClass', + ], true); + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + $managerType = new ObjectType($this->managerClass); + switch ($methodReflection->getName()) { + case 'getManagerForClass': + return TypeCombinator::addNull($managerType); + + case 'getManagers': + return new ArrayType(new IntegerType(), $managerType); + + default: + return $managerType; + } + } + +} diff --git a/src/Type/Doctrine/ManagerRegistryGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ManagerRegistryGetRepositoryDynamicReturnTypeExtension.php new file mode 100644 index 00000000..1a16e0be --- /dev/null +++ b/src/Type/Doctrine/ManagerRegistryGetRepositoryDynamicReturnTypeExtension.php @@ -0,0 +1,57 @@ +registryClass = $registryClass; + $this->repositoryClass = $repositoryClass; + } + + public function getClass(): string + { + return $this->registryClass; + } + + public function isMethodSupported(MethodReflection $methodReflection): bool + { + return $methodReflection->getName() === 'getRepository'; + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + if (count($methodCall->args) === 0) { + return ParametersAcceptorSelector::selectSingle( + $methodReflection->getVariants() + )->getReturnType(); + } + $argType = $scope->getType($methodCall->args[0]->value); + if (!$argType instanceof ConstantStringType) { + return new MixedType(); + } + + return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass); + } + +} diff --git a/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php new file mode 100644 index 00000000..00598c3f --- /dev/null +++ b/src/Type/Doctrine/ObjectManagerFindDynamicReturnTypeExtension.php @@ -0,0 +1,54 @@ +getName(), [ + 'find', + 'getReference', + 'getPartialReference', + ], true); + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + $mixedType = new MixedType(); + if (count($methodCall->args) === 0) { + return $mixedType; + } + $argType = $scope->getType($methodCall->args[0]->value); + if (!$argType instanceof ConstantStringType) { + return $mixedType; + } + + $type = new ObjectType($argType->getValue()); + if ($methodReflection->getName() === 'find') { + $type = TypeCombinator::addNull($type); + } + + return $type; + } + +} diff --git a/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php new file mode 100644 index 00000000..349a9df5 --- /dev/null +++ b/src/Type/Doctrine/ObjectManagerGetRepositoryDynamicReturnTypeExtension.php @@ -0,0 +1,57 @@ +managerClass = $managerClass; + $this->repositoryClass = $repositoryClass; + } + + public function getClass(): string + { + return $this->managerClass; + } + + public function isMethodSupported(MethodReflection $methodReflection): bool + { + return $methodReflection->getName() === 'getRepository'; + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + if (count($methodCall->args) === 0) { + return ParametersAcceptorSelector::selectSingle( + $methodReflection->getVariants() + )->getReturnType(); + } + $argType = $scope->getType($methodCall->args[0]->value); + if (!$argType instanceof ConstantStringType) { + return new MixedType(); + } + + return new ObjectRepositoryType($argType->getValue(), $this->repositoryClass); + } + +} diff --git a/src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php b/src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php new file mode 100644 index 00000000..0e1d14ec --- /dev/null +++ b/src/Type/Doctrine/ObjectRepositoryDynamicReturnTypeExtension.php @@ -0,0 +1,52 @@ +getName(); + return strpos($methodName, 'findBy') === 0 + || strpos($methodName, 'findOneBy') === 0 + || $methodName === 'findAll' + || $methodName === 'find'; + } + + public function getTypeFromMethodCall( + MethodReflection $methodReflection, + MethodCall $methodCall, + Scope $scope + ): Type + { + $calledOnType = $scope->getType($methodCall->var); + if (!$calledOnType instanceof ObjectRepositoryType) { + return new MixedType(); + } + $methodName = $methodReflection->getName(); + $entityType = new ObjectType($calledOnType->getEntityClass()); + + if ($methodName === 'find' || strpos($methodName, 'findOneBy') === 0) { + return TypeCombinator::addNull($entityType); + } + + return new ArrayType(new IntegerType(), $entityType); + } + +} diff --git a/src/Type/Doctrine/ObjectRepositoryType.php b/src/Type/Doctrine/ObjectRepositoryType.php new file mode 100644 index 00000000..f5538b35 --- /dev/null +++ b/src/Type/Doctrine/ObjectRepositoryType.php @@ -0,0 +1,30 @@ +entityClass = $entityClass; + } + + public function getEntityClass(): string + { + return $this->entityClass; + } + + public function describe(VerbosityLevel $level): string + { + return sprintf('%s<%s>', parent::describe($level), $this->entityClass); + } + +}