28

To be consistent over my coding style, I'd like to use camelCase to access attributes instead of snake_case. Is this possible in Laravel without modifying the core framework? If so, how?

Example:

// Database column: first_name echo $user->first_name; // Default Laravel behavior echo $user->firstName; // Wanted behavior 

3 Answers 3

36

Create your own BaseModel class and override the following methods. Make sure all your other models extend your BaseModel.

use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; class BaseModel extends Model { // Allow for camelCased attribute access public function getAttribute($key) { return parent::getAttribute(Str::snake($key)); } public function setAttribute($key, $value) { return parent::setAttribute(Str::snake($key), $value); } } 

Then for usage:

// Database column: first_name echo $user->first_name; // Still works echo $user->firstName; // Works too! 

This trick revolves around forcing the key to snake case by overriding the magic method used in Model.

Sign up to request clarification or add additional context in comments.

3 Comments

You also have to extend __isset() and __unset() methods. Otherwise isset(), empty() and unset() functions will not work properly with camel case keys. I spent half a day on this bug.
Is this also possible as trait?
FYI I rolled back the edit that a user made a few years ago to your answer because a) they were rewriting your answer beyond the scope of a minor edit, and b) because the code inserted was plagiarized directly from another answer. I followed up with a small edit to your original code to actually address compatibility issues.
25

Since SO doesn't allow pasting code snippets in comments, I'm posting this as a new answer.

To make sure that eager loading does not break, I had to modify @Lazlo's answer. When accessing eagerly loaded relations by a different key, they are reloaded.

use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; class BaseModel extends Model { public function getAttribute($key) { if (array_key_exists($key, $this->relations)) { return parent::getAttribute($key); } else { return parent::getAttribute(Str::snake($key)); } } public function setAttribute($key, $value) { return parent::setAttribute(Str::snake($key), $value); } } 

2 Comments

can you explain the issue that you solved here? i'm not really following that verification you do on the relations array?
let's say you run the query User::with('likedPosts'), it will be stored as $user->attributes['likedPosts']. However, when you override getAttribute and change everything into snake_case, then it would try to access $user->attributes['liked_posts'] when you write $user->likedPosts, which doesn't exist. Then laravel will lazy load the relationship, even though the relationship was already loaded (as likedPosts). To prevent this, the if statement is necessary.
7

Just thought I'd post this in case it helps anyone else. Though the answer by Bouke is great it does not address lazy-loaded relations that use a camel-case name. When this occurs we simply need to check for the method name in addition to the other checks. The following is what I did:

use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Str; class BaseModel extends Model { public function getAttribute($key) { if ( array_key_exists($key, $this->relations) || method_exists($this, $key) ) { return parent::getAttribute($key); } else { return parent::getAttribute(Str::snake($key)); } } public function setAttribute($key, $value) { return parent::setAttribute(Str::snake($key), $value); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.