Laravel 带通配符 (*) 的模型访问器和修改器

Laravel Model Accessor and Mutator with wildcard (*)

问题

我想为一个模型属性设置访问器和修改器,但要使用通配符 我为不同的语言存储了属性,称为 tags_en、tags_es、Tags_fr 等。对于 (8) 语言标签

我想在 Tag 模型中为所有 8 种语言子类型设置一个访问器和一个修改器 once对每个方法使用一对 accessor/mutator 方法。

通常人们会对它们中的每一个进行以下操作,例如tags_en

public function getTagsEnAttribute($tags){
    return join(', ', json_decode($tags));
}

public function setTagsEnAttribute($tags){
    $this->attributes['tags_en'] =
        json_encode(
            array_map('trim', explode(',', $tags))
        );
}

然后我必须为每种语言的标签重复它们,目前有 8 种语言,这是不实用的。

我的Objective

使用类似通配符的访问器和修改器的任何方式(当然不能这样工作):

public function getTagsWildcardAttribute($tags){
    return join(', ', json_decode($tags));
}

类似于:

foreach ($tagsAttributes as $TagAttribute){
    //method building code for each tags language
}

存在类似的 Laravel 验证通配符的想法

我认为可能有一种方法可以通过使用通配符的 laravel 模型 class 来完成。这类似于 Validator,您可以在其中验证数组的每个元素,如下所示:

$validator = Validator::make($request->all(), [ 
    'person.*.email' => 'email|unique:users', 
    'person.*.first_name' => 'required_with:person.*.last_name', 
]);

问题:

  1. 如果这些模型 带有通配符 的访问器和修改器在当前 laravel 框架中不可用 - 您是否同意我认为这值得在下一个 laravel 版本中 添加 吗?
  2. 如果是这样,那么 如何正式要求 laravel 制造商在即将发布的版本中考虑这一点
  3. Whosebug 工作人员能否代表我们向 laravel 构建者提出改进(如果他们看到了)?

您可以扩展 castAttribute()setAttribute() 方法。

protected function castAttribute($key, $value) {
        if (is_null($value)) {
            return $value;
        }

        if ($this->isTagCastable($key)) {
            return join(', ', json_decode($value));
        }

        return parent::castAttribute($key, $value);
    }

public function setAttribute($key, $value)
{
    if ($this->isTagCastable($key)) {
        $this->attributes[$key] =
            json_encode(
                array_map('trim', explode(',', $value))
            );
    }

    return parent::setAttribute($key, $value);
}

protected function isTagCastable($key) {
    return preg_match('/tags_[a-z]{2}/', $key);
}

我不太清楚你的数据库是如何设置的,但据我了解,它有一个 table,其中的列名为 tags_entags_frtags_de,等等

这是一个想法:

  1. 添加一个 属性 来保存您想要 set/get
  2. 的列
  3. $casts
  4. 中创建自定义类型
  5. 覆盖 boot() 方法并使用它来设置 creatingupdating
  6. 上的标签
  7. 重写 castAttribute($key, $value) 方法并在您检索它时使用它来转换值(这将像访问器一样工作)

看起来像这样

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    protected static $tags = [
        'tags_en',
        'tags_fr',
        'tags_de',
    ];

    public static function boot()
    {
        static::creating(function ($model) {
            foreach (static::$tags as $tag) {
                // You can customize exactly what you need to do here
                $model->$tag = json_encode($model->tag);
            }

            unset($model->tag);
        });

        static::updating(function ($model) {
            foreach (static::$tags as $tag) {
                // You can customize exactly what you need to do here
                $model->$tag = json_encode($model->tag);
            }

            unset($model->tag);
        });

        parent::boot();
    }

    /**
     * Cast an attribute to a native PHP type.
     *
     * @param  string  $key
     * @param  mixed  $value
     * @return mixed
     */
    protected function castAttribute($key, $value)
    {
        if (in_array($key, static::$tags)) {
            return join(', ', (array) json_decode($value));
        }

        parent::castAttribute($key, $value);
    }
}

创建模型实例时:

$t = App\MyModel::create([
    'name' => 'My Tags',
    'tag' => ['key' => 'value', 'key2' => 'value2']
]);

然后当您检索实例时:

$t = App\MyModel::find($id);
echo $t->tags_en; // This will be handled by the `castAttribute($key, $value)` override

关于您的最后 3 个问题:如果您认为它应该包括在内,那么最好的办法是 a) 通过 GitHub 存储库询问或更好 b) 将其编码并放入 PR。 Stack Overflow 工作人员与 Laravel 无关,因此他们不能也不会也不会做任何事情。

有一个解决方案,Eloquent Mutators https://github.com/topclaudy/eloquent-mutators

安装包后,您将能够为您的 Eloquent 模型注册自定义 accessors/mutators 扩展。