foundry icon indicating copy to clipboard operation
foundry copied to clipboard

Usage of `repository()` + PHPStan makes unfixable error

Open er1z opened this issue 2 years ago • 9 comments

Suppose:

$repo = MyFactory::repository();
$subscription = $repo->customRepoMethod($user);

Will make PHPStan screaming. So tried:

/** @var RepositoryProxy<My>|MyRepository $repo */
$repo = MyFactory::repository();
$subscription = $repo->customRepoMethod($user);

but it's no longer possible: https://phpstan.org/blog/phpstan-1-10-comes-with-lie-detector

Any idea how to solve this?

er1z avatar Apr 04 '23 09:04 er1z

hello @er1z

do you have in your factory the phpstan-method phpdoc suggested in the doc?

there is a specific annotation for the repository() method:

/**
 * @phpstan-method static RepositoryProxy<Post> repository()
 */

nikophil avatar Apr 04 '23 10:04 nikophil

How does it solve the problem that I need to have signatures of proxied repository?

er1z avatar Apr 04 '23 16:04 er1z

the phpdoc I gave you above should fix it: it gives some hints to phpstan that repository() method returns a RepositoryProxy<YourEntity> and the RepositoryProxy is a mixin of EntityRepository so this should work https://github.com/zenstruck/foundry/blob/1.x/src/RepositoryProxy.php#L26

Edit: for custom repo methods, maybe you can change the annotatio on phpstan-method to the one you used with @var. I've still never used phpstan with this new option, so not sure if this will work 🤔

nikophil avatar Apr 04 '23 18:04 nikophil

Yes, all this issue is about custom repository methods. And it won't work anymore due to the reason described on PHPStan's website.

Now it tells that (don't remember exact error) that MyRepository is not a derivative of returned type RepositoryProxy. And the only solution is to put it into ignores.

Gonna check if annotation like this work via phpstan-method tomorrow.

er1z avatar Apr 04 '23 20:04 er1z

Sounds like, in addition to the new phpstan mode not trusting vars, it doesn't trust mixins either.

kbond avatar Apr 05 '23 01:04 kbond

I've made some tests here, using phpstan 1.10 + bleeding edge and everything is OK if @phpstan-method is updated to:

@phpstan-method static MyRepository&RepositoryProxy<MyEntity> repository()

this might be a lie, because that's not the real type, but phpstan does not complains about it.

(and BTW, it seems to me that @mixin is still well understood)

However, I'm wondering if we should not change the generic type of RepositoryProxy: maybe it should be

/**
 * @mixin TProxiedRepository
 *
 * @template TProxiedObject of object
 * @template TProxiedRepository of object
 */
final class RepositoryProxy implements ObjectRepository

and in the factories we should document like this:

@phpstan-method static RepositoryProxy<MyCutomRepository, MyEntity> repository()
// or, if no custom repo exists
@phpstan-method static RepositoryProxy<ObjectRepository<MyEntity>, MyEntity> repository()

WDYT?

nikophil avatar Apr 07 '23 08:04 nikophil

However, I'm wondering if we should not change the generic type of RepositoryProxy: maybe it should be

If this fixes the phpstan issue I'm in favor of this. Feels less hacky than your initial solution.

kbond avatar Apr 07 '23 15:04 kbond

Yes, but after reflexion, I'm wondering if this won't break static analysis on client side 🤔 for factories which already have the annotation... PhpStan will say the template type is not fullfilled

nikophil avatar Apr 07 '23 16:04 nikophil

if this PR gets accepted, I think we should wait for it before fixing this issue

nikophil avatar Apr 23 '23 18:04 nikophil

I think this problem is now solved in v2

nikophil avatar Jun 21 '24 15:06 nikophil