Eloquent 的 First 或 Create 在检查记录是否存在之前不考虑 mutator?

Beb*_*ves 5 laravel

想象一下我有以下模型:

class Link extends Model
{
    protected $fillable = ['path', 'secret'];

    public function setSecretAttribute($value)
    {
        $this->attributes['secret'] = sha1($value);
    }
}
Run Code Online (Sandbox Code Playgroud)

以及以下代码:

$link = Link::firstOrCreate(['path' => $someValue, 'secret' => $anotherValue]);
Run Code Online (Sandbox Code Playgroud)

我的代码是否有问题,或者“firstOrCreate”在检查注册表是否已存在时忽略变异器?如果它忽略,我只需将 sha1 加密添加到“anotherValue”即可获得我期望的行为。但我的问题是,这不是多余的吗?

mik*_*n32 0

这个问题没有太多细节,但如果path是唯一标识符,则可以使用 的第二个参数轻松完成Model::firstOrCreate()

如果在数据库中找不到模型,则会插入一条记录,其中包含将第一个数组参数与可选的第二个数组参数合并而产生的属性。

所以你的代码看起来像这样:

$link = Link::firstOrCreate(
    ['path' => $someValue],
    ['secret' => $anotherValue]
);
Run Code Online (Sandbox Code Playgroud)

如果需要两个值来唯一标识记录,您可以简单地进行条件检查:

$link = Link::where('path', $someValue)
    ->where('secret', sha1($anotherValue))
    ->first();

if (!$link) {
    Link::create(['path' => $someValue, 'secret' => $anotherValue]);
}
Run Code Online (Sandbox Code Playgroud)

请注意,变异器仅适用于通过 Eloquent 方法完成的数据库写入。当您读取数据库时,您必须手动散列该值,就像我所做的那样。


为了避免手动散列值,最好的选择是模型上的查询范围,如下所示:

class Link extends Model
{
    protected $fillable = ['path', 'secret'];

    public function setSecretAttribute($value)
    {
        $this->attributes['secret'] = sha1($value);
    }

    public function scopeSecretHashOf($query, $secret)
    {
        return $query->where('secret', '=', sha1($secret));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样使用:

$link = Link::where('path', $someValue)
    ->whereSecretHashOf($anotherValue)
    ->first();

if (!$link) {
    Link::create(['path' => $someValue, 'secret' => $anotherValue]);
}
Run Code Online (Sandbox Code Playgroud)

理论上,您可以使用自定义语法拦截并重写查询,但这可能会花费更多的精力。