如何使用 laravel-model-status 包按 Laravel 中的最新状态进行过滤?

How to filter by latest status in Laravel using laravel-model-status package?

当前系统:
我正在使用 Laravel 和 Spatie 包 laravel-model-status.

需要:
以下是我正在寻找的正式描述:

Get a list of users whose latest status in set S is the status T.

基本上,我正在寻找一个 Eloquent 可以变成本地范围的示例 scopeLatestStatusEquals($T, ...$setS)

这是它的用法:

// Set of statuses to check for latest status:
$setS = ['status 1', 'status 2'];

// The latest status we want to filter
$T = 'status 2';

$result = MyModel::latestStatusEquals($T, $setS)->get();

背景:
目前,我正在获取所有用户的列表,然后在集合中进行过滤。

// Set of statuses to check for latest status:
$setS = ['status 1', 'status 2'];

// The latest status we want to filter
$T = 'status 2';

// The filtering using a collection:
$result = MyModel::get()->filter(function($model, $key){ 

  return $model->latestStatus($setS)->name == $T;

});

问题与性能和可维护性有关。理想情况下,这将使用 Eloquent ORM(而不是过滤集合)来提高性能,并且使用范围更清晰。

编辑:
这是我在 SQL:

中的写法
select * 
from users u 
where u.id in (

    select s.model_id
    from statuses s
    where s.id in (

        -- Get the latest status from the set ('a', 'b', 'c')
        select max(s2.id)
        from statuses s2
        where
            s2.model_type = 'App\Models\User'
            and s2.name in ('a', 'b', 'c')
        group by s2.model_id
                            
    )

    -- Return only rows where the latest status is 'b'
    and s.name = 'b'
    
);

scopeCurrentStatus() on hasStatus 将检索所有匹配 $setS 的用户状态,然后 bc 仍然在查询生成器上我认为这样做会做到:(未测试)

public function scopeLatestStatusEquals($query, $T, ...$setS)
{
    $query->where(function(Builder $query) use ($setS) {
         $query->currentStatus($setS)
     })->where('name', $T);
]

这是我想出的:

public function scopeLatestStatusEquals(EloquentBuilder $builder, $names, $valid_names = null) {

    $names = Arr::wrap($names);

    // Return models with statuses of a certain criteria
    $built = $builder
        ->whereHas('statuses', function ($query) use ($names, $valid_names) {

            // Latest statuses that match the provided $names
            $query
                ->whereIn('name', $names)
                ->whereIn('id', function($query) use ($valid_names) {

                        // Latest statuses
                        $query
                            ->selectRaw('max(s2.id)')
                            ->from('statuses as s2')
                            ->where('s2.model_type', $this->getStatusModelType());

                        if ($valid_names) {
                            $query->whereIn('s2.name', $valid_names);
                        }
                        else {
                            // pass
                        }

                        // Grouping by model ID
                        $query->groupBy('s2.'.$this->getModelKeyColumnName());


                    }
                );

        });

    return $built;

}

public function scopeLatestStatusMissing(EloquentBuilder $builder, $valid_names = null) {

    // Return models with statuses of a certain criteria
    $built = $builder
        ->whereDoesntHave('statuses', function ($query) use ($valid_names) {

            // Missing latest statuses
            $query
                ->whereIn('id', function($query) use ($valid_names) {

                        // Latest statuses
                        $query
                            ->selectRaw('max(s2.id)')
                            ->from('statuses as s2')
                            ->where('s2.model_type', $this->getStatusModelType());

                        if ($valid_names) {
                            $query->whereIn('s2.name', $valid_names);
                        }
                        else {
                            // pass
                        }

                        // Grouping by model ID
                        $query->groupBy('s2.'.$this->getModelKeyColumnName());


                    }
                );

        });

    return $built;

}