Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jrdavidson's avatar

Larastan Reporting Error with Collection::each method

I'm currently running Larastan version 2.4.0 and have also ran the `./vendor/bin/phpstan clear-result-cache`` but still getting the same error being reported.

Does anyone know why this error would be reported.

  :34    Parameter #1 $callback of method                                                               
         Illuminate\Support\Collection<int,Illuminate\Database\Eloquent\Model>::each() expects          
         callable(Illuminate\Database\Eloquent\Model, int): mixed, Closure(App\Models\User): mixed   
         given. 
if ($group->potentialMembers>isNotEmpty()) {
    $group->potentialMembers->each(
        fn (\App\Models\User $user, int $key) => UserJoinGroupAction::run($user, $group, $startDate)
    );
}

UserJoinGroupAction

<?php

declare(strict_types=1);

namespace App\Actions\Groups;

use App\Actions\Users\UserJoinTeamAction;
use App\Exceptions\CannotBeActivatedException;
use App\Models\Group;
use App\Models\User;
use Illuminate\Support\Carbon;
use Lorisleiva\Actions\Concerns\AsAction;

class ActivateGroupAction extends BaseGroupAction
{
    use AsAction;

    /**
     * Activate a group.
     *
     */
    public function handle(Group $group, ?Carbon $startDate = null): void
    {
        throw_if($group->canBeActivated(), CannotBeActivatedException::class);

        $startDate ??= now();

        if ($group->potentialMembers->isNotEmpty()) {
            $group->potentialMembers->each(
                fn (User $user, int $key) => UserJoinGroupAction::run($user, $group, $startDate)
            );
        }

        $this->groupRepository->activate($group, $startDate);
    }
}
<?php

declare(strict_types=1);

namespace App\Actions\Users;

use App\Models\User;
use Illuminate\Support\Carbon;
use Lorisleiva\Actions\Concerns\AsAction;

class UserJoinGroupAction extends BaseUserAction
{
    use AsAction;

    /**
     * EUser can join goup.
     */
    public function handle(User $user, Group, $group, ?Carbon $startDate = null): void
    {
        $startDate ??= now();

        $this->userRepository->joinGroup($user, $group, $startDate);
    }
}

Group

 public function potentialMembers(): MorphToMany
{
        return $this->morphedByMany(User::class, 'member')
            ->using(GroupMember::class)
            ->withPivot(['joined_at', 'left_at']);
}
0 likes
10 replies
LaryAI's avatar
Level 58

The error is being reported because the each method expects a callable that takes two parameters, the first being the Eloquent Model and the second being the index. In the code example, the callable is a closure that only takes one parameter, the Eloquent Model.

To fix this, you can update the closure to take two parameters, like so:

if ($group->potentialMembers>isNotEmpty()) {
    $group->potentialMembers->each(
        fn (\App\Models\User $user, int $key) =&gt; UserJoinGroupAction::run($user, $group, $startDate, $key)
    );
}

Then, update the run method in the UserJoinGroupAction class to accept the second parameter:

public function run(User $user, Team $team, ?Carbon $startDate = null, int $key)
{
    $startDate ??= now();

    $this->userRepository->join($user, $group, $startDate, $key);
}

This should resolve the error.

jrdavidson's avatar

Unfortunately AI isn't helpful on this one as its suggestion doens't solve the problem.

MohamedTammam's avatar

@jrdavidson That's weird, even the error message doesn't match the code.

What if you try the following?

$group->potentialMembers->each( function(\App\Models\User $user, int $key) use($startDate) { 
        UserJoinGroupAction::run($user, $group, $startDate); 
    }
);
LaraBABA's avatar

This Ai auto answering thing will have a ripple effect for this forum as people will go directly to chatGPT and won't see the membership video sales and other goodies here anymore. Marketing wise, I would not have done that if I was them as it can hurt this forum more than help.

carlklein's avatar
Level 7

Hi,

I think the solution is to let Larastan know what is returned from the potentialMembers method. I don't have a MorphToMany in the projects I'm working on but I think it works like a BelongsToMany. It will probably be something like this:

/**
  * @return morphedByMany<User>
  */
public function potentialMembers(): MorphToMany
{
        return $this->morphedByMany(User::class, 'member')
            ->using(GroupMember::class)
            ->withPivot(['joined_at', 'left_at']);
}
3 likes

Please or to participate in this conversation.