calebdw / larastan

⚗️ Adds code analysis to Laravel improving developer productivity and code quality.
MIT License
4 stars 0 forks source link

Eloquent with #17

Open makroxyz opened 2 months ago

makroxyz commented 2 months ago

Description

Starting from Laravel 11.23.* the following error

Parameter 1 $relations of method Illuminate\Database\Eloquent\Builder<Domain\Monitor\Models\MonitorResource>::with() expects array<array|(Closure(Illuminate\Database\Eloquent\Relations\Relation<*, *, *>):  mixed)|string>|string, array{monitorable: Closure(Illuminate\Database\Eloquent\Relations\MorphTo): void} given

Laravel code where the issue was found

$resources = Resource::whereIn('resource_id', $requestResources)
    ->with([
        'monitorable' => function (MorphTo $morphTo) {
             $morphTo->morphWith([
                 Service::class => [
                     'relation1',
                     'relation2',
                 ],
             ]);
          },
     ]);
calebdw commented 2 months ago

Hello!

Thanks for your report, however, this is expected as closure parameter types are invariant. See:

I thought this would be fine since most methods you need are defined on the Relation but morphWith is only defined on the MorphTo relation so you do need to type it.

I'll open an issue with PHPStan to see if there's a way to solve this problem. In the meantime you can override the type inside the closure:

$resources = Resource::query()
    ->whereIn('resource_id', $requestResources)
    ->with([
        'monitorable' => function ($morphTo) {
             /** @var MorphTo $morphTo */
             $morphTo->morphWith([
                 Service::class => ['relation1', 'relation2'],
             ]);
          },
     ]);
makroxyz commented 2 months ago

Sorry, but workaround doesn't work...

PHPDoc tag @var for variable $morphTo contains generic class Illuminate\Database\Eloquent\Relations\MorphTo but does not specify its types: TRelatedModel, TDeclaringMode
calebdw commented 2 months ago

So then use:

/** @var MorphTo<*, *> $morphTo */
vixducis commented 1 week ago

I understand the workaround but changing native PHP types to docblocks hampers type checking at runtime and strongly reduces readability (at least in my opinion). This occurs hundreds of times in my codebase, making it a considerable time investment to change the types (and to change them back once this has been resolved).

Is there any option to stub this out until a definite solution is conceived?

calebdw commented 1 week ago

@vixducis, you can just create a regex ignore rule that matches on Builder, ::with\(, MorphType, etc.