Quick Life Hacks with the Eloquent Model

Hi folks,

It’s no secret that I love Laravel, and especially love Eloquent. This post isn’t about why various people don’t like Eloquent, etc, etc. but just some “life hacks” of working with Eloquent.

#1 – Naming Conventions

I personally like to use the following naming convention on my databases (using a forum as an example)

forums
forums_topics
forums_topics_replies

Whereas Eloquent would expect the following:

forums
forum_topics
forum_topic_replies

I personally dislike this, for no other reason than I like to be able to see what’s being owned by what at a very quick glance. Additionally, namespacing; I like to namespace my Models, at the very least into a Model namespace, but often I like to further namespace these to represent the ownership of the data; so I end up with something like (I’m using a directory structure, because PSR-4 namespaces follow this anyway)

app/
- Model/
- - Forum
- - ForumTopic
- - ForumTopicReply

My only issue with this is that the Model namespace can end up huge, and with classes with some really ridiculously long names. So I prefer to break this down like so:

app/
- Model/
- - Forum
- - Forum/
- - - Topic
- - - Topic/
- - - - Reply

I realise this begins to look like overkill, but I find it particularly useful when separating functionality by module or something like that.

The Autonaming

The above means I have two options, number one is to follow the convention to the letter. Option two is to overwrite the naming convention on a base model, from which I then extend. This base/abstract model contains the following method:

/**
 * Overwrite the autonaming conventions
 * @return string
 */
public function getTable()
{
    $class = substr(get_class($this), strlen(self::MODEL_NAMESPACE));
    $namespaces = explode('\\', $class);
    foreach($namespaces as &$namespace){
        if(substr($namespace, -1) == 'y'){
            $namespace = strtolower(substr($namespace, 0, -1) . 'ies');
        } else {
            $namespace = strtolower($namespace . 's');
        }
    }
    return implode('_', $namespaces);
}

Note: You will need to have the MODEL_NAMESPACE constant declared as well

All this does is turned app\Model\Forum\Topic into forums_topics, but it’s pretty useful

PSR-2 properties

So the other thing I find occasionally annoying is that when writing PHP my properties follow the PSR-2 naming convention (camelCaseForVariables) – but using eloquent I am forced to snake_case_columns because (understandably) this is what is in the database.

By adding the following 3 methods to your base model you can use PSR-2 compliant field names. So that created_at becomes createdAt; without having to modify the database;

/**
 * Overwrite the getter so that we can use camelCase field names
 * @param string $property
 * @return mixed
 */
public function __get($property)
{
    return parent::__get($this->convertToSnakeCase($property));
}

/**
 * Overwrite the setter so that we can use camelCase field names
 * @param string $property
 * @param mixed $value
 */
public function __set($property, $value)
{
    parent::__set($this->convertToSnakeCase($property), $value);
}
/**
 * Turn a camelCase string into snake_case
 * @param $string
 * @return mixed
 */
protected function convertToSnakeCase($string)
{
    return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $string));
}

Quite simply, all these methods are doing is plugging into the original getter and setter, but first converting camelCase to snake_case – so that throughout my code I can refer to these fields in a way which is fitting with the rest of my code, which conforms to PSR-2

There you have it

A couple of very quick, but very useful, ways to extend the base Eloquent Model so that it is in better fitting with the rest of your code base and database standards (or mine, anyway)

Tagged , , , , , ,

I'd love to hear your opinion on what I've written. Anecdotes are always welcome.

%d bloggers like this: