Reputation: 255
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:
Upvotes: 0
Views: 2030
Reputation: 819
There is a solution for that, Eloquent Mutators https://github.com/topclaudy/eloquent-mutators
After installing the package, you would be able to register custom accessors/mutators extensions for your Eloquent models.
Upvotes: 0
Reputation: 3961
It's a bit unclear to me as to how your Database is setup, but from what I understand, it has a table with columns named tags_en
, tags_fr
, tags_de
, etc.
Here's an idea:
$casts
boot()
method and use it to set the tagson creating
and updating
castAttribute($key, $value)
method and use it to cast the value back when you retrieve it (this will function like an accessor)It would look something like this
<?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);
}
}
When you create an instance of the model:
$t = App\MyModel::create([
'name' => 'My Tags',
'tag' => ['key' => 'value', 'key2' => 'value2']
]);
Then when you retrieve an instance:
$t = App\MyModel::find($id);
echo $t->tags_en; // This will be handled by the `castAttribute($key, $value)` override
Regarding your last 3 questions: If you think it should be included, then the best thing is to a) ask via the GitHub repo or even better b) code it up and put in a PR. Stack Overflow staff has nothing to do with Laravel so they can't and won't and wouldn't be able to do anything.
Upvotes: 1
Reputation: 2503
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);
}
Upvotes: 1