How are the attributes of a Model accessed in Laravel?

Posted in Eloquent , Intermediate , Laravel 22 Feb 2019

The most common approach to access attributes of a Model is to use $modelobject->attribute.

In this post , we will discuss what happens behind the scenes when an attribute is accessed using above approach. The explanation would also clarify how accessors work in Eloquent. Accessors allow us to format/manipulate eloquent attribute values after they are fetched from DB by Model.

Laravel calls __get() magic method behind the scenes when $modelobject->attribute is used if the requested attribute property is not a public property of the model.

__get() is defined in Model.php as shown below

/**
 * Dynamically retrieve attributes on the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function __get($key)
{
    return $this->getAttribute($key);
}

As we can see , __get method calls getAttribute() function which further calls hasGetMutator() function.

/**
 * Get an attribute from the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function getAttribute($key)
{
    if (! $key) {
        return;
    }

    // If the attribute exists in the attribute array or has a "get" mutator we will
    // get the attribute's value. Otherwise, we will proceed as if the developers
    // are asking for a relationship's value. This covers both types of values.
    if (array_key_exists($key, $this->attributes) ||
        $this->hasGetMutator($key)) {
        return $this->getAttributeValue($key);
    }

    // Here we will determine if the model base class itself contains this given key
    // since we don't want to treat any of those methods as relationships because
    // they are all intended as helper methods and none of these are relations.
    if (method_exists(self::class, $key)) {
        return;
    }

    return $this->getRelationValue($key);
}

hasGetMutator() function is responsible for getting all the accessors defined for model.

/**
 * Determine if a get mutator exists for an attribute.
 *
 * @param  string  $key
 * @return bool
 */
public function hasGetMutator($key)
{
    return method_exists($this, 'get'.Str::studly($key).'Attribute');
}

Note: It is not mandatory to have column/field name in accessor as in some cases you may need to use a dynamic non-existing table field/property, for example, if you have a first_name and last_name field/property and you want to use both names together as a full_name property then in this case, Laravel provides a nice way to get it. All you need to do is that, create a method like:

/**
 * Get the user's full name.
 *
 * @return string
 */
public function getFullNameAttribute()
{
    return "{$this->first_name} {$this->last_name}";
}