# Extended Laravel Eloquent models to add filters to model setters

One of the tasks I find myself doing repeatedly is to filter the incoming inputs that will be stored in models. Examples of this include trimming, removing repeated or unnecessary pre/suffixes, commas or dashes in numbers, etc. This is similar to validation, but Laravel's built-in Validator does not appear to have this capability.

Mutators in Eloquent models does support this, but for large models creating one for each property will result in a lot of repeated code. I considered extending Validator to add this to the validation step, or adding a middleware to filter form requests, but it seems the easiest way would be to override the Model class' setAttribute function

use Illuminate\Database\Eloquent\Model;
use Log;

class BaseModel extends Model
{
protected $filters = []; public function setAttribute($key, $value) { if ($this->hasFilter($key)) {$value = $this->executeFilter($key, $value); } return parent::setAttribute($key, $value); } protected function hasFilter($key)
{
return array_key_exists($key,$this->filters);
}

protected function getFilter($key) { return$this->filters[$key]; } protected function executeFilter($key, $value) {$filter = $this->getFilter($key);
$rules = is_string($filter) ? explode('|', $filter) : [$filter];

foreach ($rules as$rule) {
if (is_callable($rule)) {$value = call_user_func($rule,$value);
} elseif (method_exists($this, 'filter'.ucfirst($rule))) {
$ruleMethod = 'filter'.ucfirst($rule);
$value =$this->$ruleMethod($value);
} else {
Log::warning("Unknown filter method $filter called on$key",
['model' => '', 'value' => $value]); } } return$value;
}
}


Example usage:

class Listing extends BaseModel
{
protected $filters = [ 'name' => 'trim', 'description' => 'trim', 'price' => 'price', ]; protected function filterPrice($value)
{
return (float) ltrim(trim($value), '$');
}
}


The \$filters property contains the rules needed for each property. Each rule is separated by |, and the rule has to be a function that either exist globally (ie. built-in functions or helpers), or as a method on the model prefixed with the word 'filter'.

My questions are:

1. Is there a better way to accomplish the same functionality (ie. running some functions on all inputs), at a middleware, controller or model level?
2. This implementation works (I've written a few simple tests for them to verify this), but is this good design, and can it be improved? For instance, I'm curious if this can be rewritten into a trait, which I think is preferable - I don't think it is possible, but I might have missed something