Laravel 5 Eloquent, How to set cast attribute dyna

2020-07-17 15:22发布

问题:

In laravel 5.1 there is new feature called Attribute Casting, well documented at here : http://laravel.com/docs/5.1/eloquent-mutators#attribute-casting

My question is, it is possible to make attribute casting dynamically ?

for example, I have a table with columns :

id | name          | value       | type    |
1  | Test_Array    | [somearray] | array   |
2  | Test_Boolean  | someboolean | boolean |

it is possible to set value attribute cast, depends on type field, that work both in write(create/update) and fetch ?

回答1:

You'll need to overwrite Eloquent model's getCastType() method in your model class:

protected function getCastType($key) {
  if ($key == 'value' && !empty($this->type)) {
    return $this->type;
  } else {
    return parent::getCastType($key);
  }
}

You'll also need to add value to $this->casts so that Eloquent recognizes that field as castable. You can put the default cast there that will be used if you didn't set type.

Update:

The above works perfectly when reading data from the database. When writing data, you have to make sure that type is set before value. There are 2 options:

  1. Always pass an array of attributes where type key comes before value key - at the moment model's fill() method respects the order of keys when processing data, but it's not future-proof.

  2. Explicitely set type attribute before setting other attributes. It can be easily done with the following code:

    $model == (new Model(['type' => $data['type']))->fill($data)->save();
    


回答2:

The $casts attribute it used whenever you access a field, not when it is fetched from the database. Therefore, you can update the $casts attribute after the model has been populated, and it should work fine whenever you access the value field. You just need to figure out how to update the $casts attribute when the type field is changed.

One potential option would be to override the fill() method so that it calls the parent fill() method first, and then updates the $casts attribute with the data in the type field.

Another potential option would be to abuse the mutator functionality, and create a mutator on the type field, so that whenever it changes, it would update the $casts attribute.