Skip to content

TypeFactory::build() support聽#45

Closed

Description

@dereuromark
TypeFactory::build('datetime')
    ->setUserTimezone(Configure::readOrFail('App.defaultOutputTimezone'));

yields

  52     Call to an undefined method Cake\Database\TypeInterface::setUserTimezone().  
         馃 method.notFound

is it possible for phpstan to learn also about static methods and that it is that concrete DateTimeType ?

Activity

  1. rochamarcelo commented on May 19, 2025

    @rochamarcelo
    Contributor

    It should be able to understand based on default values of TypeFactory::$_types using an extension, maybe it is also possible with annotations.

  2. rochamarcelo commented on May 20, 2025

    @rochamarcelo
    Contributor
  3. dereuromark commented on May 20, 2025

    @dereuromark
    CollaboratorAuthor

    A manual strategy could be sth like

    namespace App\PHPStan;
    
    use PhpParser\Node\Expr\StaticCall;
    use PHPStan\Analyser\Scope;
    use PHPStan\Reflection\MethodReflection;
    use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
    use PHPStan\Type\Type;
    use PHPStan\Type\ObjectType;
    use PHPStan\Type\MixedType;
    
    class TypeFactoryBuildReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension
    {
        public function getClass(): string
        {
            return \Cake\Database\TypeFactory::class;
        }
    
        public function isStaticMethodSupported(MethodReflection $methodReflection): bool
        {
            return $methodReflection->getName() === 'build';
        }
    
        public function getTypeFromStaticMethodCall(
            MethodReflection $methodReflection,
            StaticCall $methodCall,
            Scope $scope
        ): Type {
            if (count($methodCall->getArgs()) === 0) {
                return new MixedType();
            }
    
            $argType = $scope->getType($methodCall->getArgs()[0]->value);
    
            if ($argType->isString()->yes()) {
                $constantStrings = $argType->getConstantStrings();
                if (count($constantStrings) === 1) {
                    $typeName = $constantStrings[0]->getValue();
                    if ($typeName === 'datetime') {
                        return new ObjectType(\Cake\Database\Type\DateTimeType::class);
                    }
                    // Add more mappings
                }
            }
    
            return new MixedType();
        }
    }

    We should be able to automate this based on Name/Namespace I guess even.

  4. rochamarcelo commented on May 20, 2025

    @rochamarcelo
    Contributor

    Could rely on predefined values from $_types, also return null instead of MixedType to fallback to method return type

  5. rochamarcelo commented on May 20, 2025

    @rochamarcelo
    Contributor

    What do you think about using annotation instead of an extension @dereuromark ?

    This would require to add constant in the class and use that as 'template'. The existing property would refer to the new constant: protected static array $_types = self:TYPES;

    Example: https://phpstan.org/r/b7d9e97a-8d3e-4462-8b03-f30ea6942f97

  6. dereuromark commented on May 20, 2025

    @dereuromark
    CollaboratorAuthor

    Well we are mainly using it in bootstrap
    And maybe a few other places.

    The extension would just make it work out of the box :)

  7. dereuromark commented on Oct 15, 2025

    @dereuromark
    CollaboratorAuthor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions