Trucks tips

Replicate: make a copy of a row

Short one. Without deep explanations, here’s the best way to make a copy of database entry:

1$task = Tasks::find(1);2$newTask = $task->replicate();3$newTask->save();

Raw query methods

Sometimes we need to add raw queries to our Eloquent statements. Luckily, there are functions for that.

 1// whereRaw 2$orders = DB::table('orders') 3    ->whereRaw('price > IF(state = "TX", ?, 100)', [200]) 4    ->get(); 5 6// havingRaw 7Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get(); 8 9// orderByRaw10User::where('created_at', '>', '2016-01-01')11  ->orderByRaw('(updated_at - created_at) desc')12  ->get();

Order by Mutator

Imagine you have this:

1function getFullNameAttribute()2{3  return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];4}

Now, you want to order by that full_name? This won’t work:

1$clients = Client::orderBy('full_name')->get(); // doesn't work

The solution is quite simple. We need to order the results after we get them.

1$clients = Client::get()->sortBy('full_name'); // works!

Notice that the function name is different – it’s not orderBy, it’s sortBy.

BelongsTo Default Models

Let’s say you have Post belonging to Author and then Blade code:

1{{ $post->author->name }}

But what if the author is deleted, or isn’t set for some reason? You will get an error, something like “property of non-object”. Of course, you can prevent it like this:

1{{ $post->author->name ?? '' }}

But you can do it on Eloquent relationship level:

1public function author()2{3    return $this->belongsTo('App\Author')->withDefault();4}

In this example, the author() relation will return an empty App\Author model if no author is attached to the post. Furthermore, we can assign default property values to that default model.

1public function author()2{3    return $this->belongsTo('App\Author')->withDefault([4        'name' => 'Guest Author'5    ]);6}

Eloquent::when() – no more if-else’s

Many of us write conditional queries with “if-else”, something like this:

1if (request('filter_by') == 'likes') {2    $query->where('likes', '>', request('likes_amount', 0));3}4if (request('filter_by') == 'date') {5    $query->orderBy('created_at', request('ordering_rule', 'desc'));6}

But there’s a better way – to use when():

1$query = Author::query();2$query->when(request('filter_by') == 'likes', function ($q) {3    return $q->where('likes', '>', request('likes_amount', 0));4});5$query->when(request('filter_by') == 'date', function ($q) {6    return $q->orderBy('created_at', request('ordering_rule', 'desc'));7});

It may not feel shorter or more elegant, but the most powerful is passing of the parameters:

1$query = User::query();2$query->when(request('role', false), function ($q, $role) {3    return $q->where('role_id', $role);4});5$authors = $query->get();

Order by relationship

A little more complicated “trick”. What if you have forum topics but want to order them by latest post? Pretty common requirement in forums with last updated topics on the top, right? First, describe a separate relationship for the latest post on the topic:

1public function latestPost()2{3    return $this->hasOne(\App\Post::class)->latest();4}

And then, in our controller, we can do this “magic”:

1$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');

WhereX

There’s an elegant way to turn this:

1$users = User::where('approved', 1)->get();

Into this:

1$users = User::whereApproved(1)->get();

Yes, you can change the name of any field and append it as a suffix to “where” and it will work by magic. Also, there are some pre-defined methods in Eloquent, related to date/time:

1User::whereDate('created_at', date('Y-m-d'));2User::whereDay('created_at', date('d'));3User::whereMonth('created_at', date('m'));4User::whereYear('created_at', date('Y'));

Find multiple entries

Everyone knows the find() method, right?

1$user = User::find(1);

I’m quite surprised how few people know about that it can accept multiple IDs as an array:

1$users = User::find([1,2,3]);

Model properties: timestamps, appends etc.

There are a few “parameters” of an Eloquent model, in the form of properties of that class. The most popular ones are probably these:

1class User extends Model {2    protected $table = 'users';3    protected $fillable = ['email', 'password']; // which fields can be filled with User::create()4    protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized5    protected $appends = ['field1', 'field2']; // additional values returned in JSON6}

But wait, there’s more:

1protected $primaryKey = 'uuid'; // it doesn't have to be "id"2public $incrementing = false; // and it doesn't even have to be auto-incrementing!3protected $perPage = 25; // Yes, you can override pagination count PER MODEL (default 15)4const CREATED_AT = 'created_at';5const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden6public $timestamps = false; // or even not used at all

And there’s even more, I’ve listed the most interesting ones, for more please check out the code of default abstract Model class and check out all the traits used.

Relationship with conditions and ordering

This is a typical way to define relationship:

1public function users() {2    return $this->hasMany('App\User');3}

But did you know that at this point we can already add where or orderBy? For example, if you want a specific relationship for some type of users, also ordered by email, you can do this:

1public function approvedUsers() {2    return $this->hasMany('App\User')->where('approved', 1)->orderBy('email');3}