Search code examples
phplaravelwildcardaccessormutators

Laravel Model Accessor and Mutator with wildcard (*)


The issue

I would like to set accessors and mutators for one model attribute but with wildcards I have attribute stored for different languages called tags_en, tags_es, Tags_fr, etc.. for (8) language tags

I would like to set one accessor and one mutator in the Tag model for all of the 8 language sub-types once instead of using couple of accessor/mutator method for each of them.

Normally one would do the following for each of them e.g. 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))
        );
}

Then I have to repeat them for each language variety of tags which are at the moment 8 languages which is not practical.

My Objective

Any way to do accessors and mutators with a wildcard something like (which of course do not work this way):

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

or

something like:

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

Similar Laravel idea exists for Validation with wildcard

I assume that there may be a way to do it through laravel Model class using wildcard. This is similar to Validator where you can validate each element of an array like this:

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

Questions:

  1. If these model accessors and mutators with wild card are not available in current laravel framework - do you agree with me that this is worthwhile to add in the next laravel versions?
  2. If so, then how to ask laravel makers, officially, to consider this in the upcoming versions?
  3. Can Stackoverflow staff to ask laravel builders for that improvement (if they see it is) in our behalf?

Solution

  • You could extend castAttribute() and setAttribute() methods.

    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);
    }