Larastan: Support for states on new Laravel 8 factories

Created on 18 Sep 2020  路  3Comments  路  Source: nunomaduro/larastan

  • Larastan Version: 0.6.4
  • --level used: max

Description

It's seems that states on the new factories that came with Laravel 8 are not yet supported.

It would be nice if we could deduct the return type of the Model::factory() method, added by the HasFactory trait.

Laravel code where the issue was found

User::factory()->expired()->create();

I would love to help out, but I haven't got a clue where to start. If anyone could guide me, I'm very much willing to put some time and effort into this.

good first issue

Most helpful comment

For all those who currently have this problem: I solved it by specifying the static method factory with a specified return value in the PHPDoc:

/**
 * @method static UserFactory factory(mixed $parameters)
 */
class User extends Model
{
    use HasFactory;
}

All 3 comments

I would love to help out, but I haven't got a clue where to start. If anyone could guide me, I'm very much willing to put some time and effort into this.

One way of doing this would be to write a DynamicStaticMethodReturnTypeExtension.

Here's an example of one https://github.com/nunomaduro/larastan/blob/master/src/ReturnTypes/StorageDynamicStaticMethodReturnTypeExtension.php

See also: https://phpstan.org/developing-extensions/dynamic-return-type-extensions

The class could look something like this:

public function getClass(): string
{
     return Model::class;
}

public function isStaticMethodSupported(MethodReflection $methodReflection): bool
{
     return $methodReflection->getName() === 'factory';
}

public function getTypeFromStaticMethodCall(
    MethodReflection $methodReflection,
    StaticCall $methodCall,
    Scope $scope
): Type {
    $modelName = $methodReflection->getDeclaringClass()->getName();
    // Here you have to determine $factoryName from $modelName
    return new ObjectType($factoryName);
}

I haven't worked a lot with the new factories yet, so I'm not sure if there are any caveats, but I think this should be enough to make it work.

I've been spending some time on this, I've got the return type resolving the correct factory but it's still in a union type with the base factory. When i have more time I'll try to fix this.

For all those who currently have this problem: I solved it by specifying the static method factory with a specified return value in the PHPDoc:

/**
 * @method static UserFactory factory(mixed $parameters)
 */
class User extends Model
{
    use HasFactory;
}
Was this page helpful?
0 / 5 - 0 ratings