23
Sep '15

This is a quick one for those who are attempting to transition over to Eloquent from another DAL where model ‘getter’ and ‘setter’ commands are the norm, rather than directly accessing the database field as a parameter, or indeed simply for those who prefer the ‘getter’ and ‘setter’ style of field access. e.g.

$table->setName('name');
return $table->getName();

rather than

$table->name = 'name';
return $table->name;

All you need to do is to include this in a base model which all your other models can extend, then it will transparently allow you to access your database fields in whatever fashion you like:

/**
 * Magic method to handle getThing() and setThing('value') calls automatically
 *
 * @param string $method Method
 * @param array $args Arguments
 * @return mixed
 */
public function __call($method, $args) {

    $action = strtolower(substr($method, 0, 3));

    if($action == 'get' || ($action == 'set' && $args)) {
        $lc_field_name = strtolower(substr($method, 3));

        //If you're using Laravel you can use the built-in snake_case() method here instead
        $snake_field_name = strtolower(preg_replace("/(?<=[a-z0-9])([A-Z])/", "_\$1", substr($method, 3)));

        $columns = array_keys(self::attributesToArray());

        if(in_array($lc_field_name, $columns)) {
            return $this->callHelper($action, $lc_field_name, $args);
        }
        elseif(in_array($snake_field_name, $columns)) {
            return $this->callHelper($action, $snake_field_name, $args);
        }
    }
    
    return parent::__call($method, $args);
}

/**
 * Call helper
 *
 * @param string $action Action
 * @param string $field_name Field name
 * @param array $args Arguments
 * @return mixed
 */
protected function callHelper($action, $field_name, $args) {
    if($action == 'get') {
        return $this->$field_name;
    }
    else {
        $this->$field_name = $args[0];
        return $this;
    }
}

You’ll notice that as a little flexibility bonus, it will look for matching field names that are either snake case or just simply lower-cased.
It’s also worth bearing in mind here that you will get a performance increase if you cache the column list, at least at object level, so that it doesn’t have to read them fresh for every call.