Improved Eloquent Accessors / Mutators:
In the earlier versions of Laravel, the accessors and mutators were only defined by defining prefixed practices on your model such as:
public function getNameAttribute($value) { return strtoupper($value); } public function setNameAttribute($value) { $this->attributes['name'] = $value; }
However, the new version of Laravel 9.x may define them by using a single practice like
use Illuminate\Database\Eloquent\Casts\Attribute; public function name(): Attribute { return new Attribute( get: fn ($value) => strtoupper($value), set: fn ($value) => $value, ); }
Enum Eloquent Attribute Casting:
Eloquent now enables you to project the values of the attribute to PHP enums. You need to define in your $cast property the model.
use App\Enums\ServerStatus; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'status' => ServerStatus::class, ];
Once you have defined the cast on your model, the specified attribute will be automatically cast to and from an enum when you interact with the attribute:
if ($server->status == ServerStatus::provisioned) { $server->status = ServerStatus::ready; $server->save(); }
Eloquent queries:
Laravel offers one of the most powerful Active-Record implementations in the PHP world. Let’s say that you have a jobs table, along with a Job’s Eloquent model:
class Job extends Eloquent {}
We can easily perform any number of database queries, using simple, elegant PHP. No need to throw messy SQL around the room. Let’s grab all the jobs.
Job::all();
Or maybe, those orders should be returned in order, according to the release date. That’s easy:
$jobs = Job::orderBy('created_at', 'desc')->get();
What if, rather than fetching a record, we instead need to save a new order to the database. Sure, we can do that.
$job = new Job; $job->name = 'Roofing'; $job->save();
Disable Laravel’s Eloquent timestamps:
namespace App; use Illuminate\Database\Eloquent\Model; class MyModel extends Model { public $timestamps = false; }
Easy search with Eloquent:
a. A simple technique to create various filters aggregated in Eloquent is with query string
public function index(Request $request) { $search = function ($query) use($request) { foreach ($request->only('title', 'content', 'description') as $name => $value) { strlen($value) && $query->where($name, 'LIKE', "%{$value}%"); } }; return Post::where($search)->paginate(); }
Boot Method
a. There is a magical place called boot() in an Eloquent model where you can override default behavior:
class Job extends Model { public static function boot() { parent::boot(); static::updating(function($model) { // do some logging // override some property like $model->something = transform($something); }); } }
If you want to generate some DB column value when creating a record, add it to the model’s boot() method. For example, if you have a field “number” and want to assign the next available number to the new record (like job::max(‘number’) + 1), do this:
class Job extends Model { protected static function boot() { parent::boot(); Job::creating(function($model) { $model->number = Job::max('number') + 1; }); } }
Count on relationship
Laravel allows you to return to the total number of rows of a relationship module instead of getting a full data object.
Define a relation jobs public function jobs() { return $this->hasMany(job::class); } Now you can use it like this. $customers = Customer::withCount('jobs')->get(); foreach ($customers as $customer) { echo $customer->jobs_count; }
Laravel Eloquent update if it is changed or created
You can check with a recently created method to identify if the model is created recently or not.
$customer = Customer::create($attributes); if($customer->wasRecentlyCreated) { // do something }
The IsDirty method is used to check if the model attribute has changed or not.
$customer = Customer::first(); $customer->isDirty(); //false $customer->name = "Bill Holland"; $customer->isDirty(); //true.. Above customer name has changed.. So it will return true now.
Add conditions (where) and order by on relationships
a. The following is a typical way in which a relationship is defined:
public function users() { return $this->hasMany('App\User'); }
We can also add where or orderBy at this point.
public function users() { return $this->hasMany('App\User')->where('approved', 1)->orderBy('id', desc); }
Model Properties, Append (add custom attribute), primaryKey (Change Primary ID column), Stop to fill default timestamps.
class User extends Model { protected $table = 'users'; protected $fillable = ['email', 'password']; // which fields can be filled with User::create() protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized protected $appends = ['field1', 'field2']; // These two fields will append in the user model instance }
These two fields will append in the user model.
// here is more
protected $primaryKey = 'uuid'; //we can set other field like uuid as a primary key public $incrementing = false; // and it doesn't even have to be auto-incrementing! protected $perPage = 25; // Yes, overriding pagination count PER MODEL (default 15) is possible const CREATED_AT = 'created_at'; const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden (When we are adding $table->timestamps(); during the creation of migration.. then laravel adds two columns in the selected table.. the columns names are created_at and updated_at.. We can create these default columns with other names with using of these two properties) public $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 the default abstract Model class and check out all the traits used.
WhereX Condition
Where(‘column_name’, ‘=’, value) to WhereColumnName(value)
a. There’s an elegant way to turn this:
$users = User::where('approved', 1)->get();
b. Into this:
$users = User::whereApproved(1)->get();
c. Also, there are several pre-defined practices or methods in Laravel Eloquent that are connected to date/time:
User::whereDate('created_at', date('Y-m-d')); User::whereDay('created_at', date('d')); User::whereMonth('created_at', date('m')); User::whereYear('created_at', date('Y'));
Eloquent::when() – no more if-else’s
a. Many of us write conditional queries with “if-else”, something like this:
$query = Author::query(); if (request('filter_by') == 'likes') { $query->where('likes', '>', request('likes_amount', 0)); } if (request('filter_by') == 'date') { $query->orderBy('created_at', request('ordering_rule', 'desc')); }
b. But there’s a better way – to use when():
$query = Author::query(); $query->when(request('filter_by') == 'likes', function ($q) { return $q->where('likes', '>', request('likes_amount', 0)); }); $query->when(request('filter_by') == 'date', function ($q) { return $q->orderBy('created_at', request('ordering_rule', 'desc')); });
c. It may not feel shorter or more elegant, but the most powerful is passing of the parameters:
$query = User::query(); $query->when(request('role', false), function ($q, $role) { return $q->where('role_id', $role); }); $users = $query->get();
Belong to default Models
a. Suppose, we have a customer and the customer can have multiple jobs.. But now we have to show the job and corresponding customer. Then we will add code in blade like this:
{{ $job->customer->name }}
b. But what if the customer 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:
{{ $job->customer->name ?? '' }}
c. But you can do it on Eloquent relationship level:
public function customer() { return $this->belongsTo('App\Customer')->withDefault(); }
i) In this example, the customer() relation will return an empty App\Customer model if no customer is attached.
d. Furthermore, we can assign default property values to that default model.
public function customer() { return $this->belongsTo('App\Customer')->withDefault([ 'name' => 'Sample Customer' ]); }
Default ordering in global scope
a. What if you want to have User::all() always be ordered by name field? You can assign a global scope. Let’s go back to the boot() method, which we mentioned already above.
protected static function boot() { parent::boot(); // Order by name ASC static::addGlobalScope('order', function (Builder $builder) { $builder->orderBy('name', 'asc'); }); }
Read more about Query Scopes here.
Raw query methods
a. Sometimes we need to add raw queries to our Eloquent statements. Luckily, there are functions for that.
// whereRaw $orders = DB::table('orders') ->whereRaw('price > IF(state = "NY", ?, 100)', [200]) ->get();
In this code snippet if order state is NY then order price will be set to 100 Price during the fetching of orders. If the order state changes from NY to any other state like NJ the order price will change to 200.
// havingRaw Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get(); In this query, Only those products will come that has more than one categories public $timestamps = false; // or even not used at all // orderByRaw User::where('created_at', '>', '2016-01-01') ->orderByRaw('(updated_at - created_at) desc') ->get();
Now, if we want to check the order by difference between updated_at and created_at starting with the maximum time taken to complete, we will use these two fields.
Now, what if we need to order by the difference between updated_at and created_at? Then we will do this thing like this.
Replicate method – To replicate the row
a. Short one. Without deep explanations, here’s the best way to make a copy of database entry:
$job = Job::find(1); $newTJob = $job->replicate(); $newTJob->save();
Chunk Method for big tables
Laravel Eloquent chunk method is used for breaking the large group of data sets into smaller groups of data sets. The following code will get all the data from database via one sql query. The user can be in thousands of data.
$users = User::all(); foreach ($users as $user) { // ... }
The following code will get all users from the database but not in one query.. This will get the 100 users in one query:
User::chunk(100, function ($users) { foreach ($users as $user) { // ... } });
Laravel Nested Relationship
Users want to see all assigned customers with their jobs.. we can do the following.
protected $with="jobs"; //it is important public function customers() { $this->hasMany('App\Customers'); } //In Job Model: public function jobs() { $this->hasMany('App\jobs'); } User::with('customers')->get(); // when this query is executed then jobs will auto fetch with eager load
Save models and relationships
Laravel Eloquent allows us to save a model and its corresponding relationship using the push() method.
class User extends Model { public function phone() { return $this->hasOne('App\Phone'); } } $user = User::first(); $user->name = "David Jones"; $user->phone->number = '1234567890'; $user->push(); // This will update both user and phone record in DB
Get original attributes
You can retrieve original values with the getOriginal Method like this.
$customer = Customer::first(); // Customer name is George George $customer->name = "Bill Holland"; $customer->getOriginal('name'); // it will return George George
Laravel allows us to delete all child records if the parent record is being deleted. We have to use the Model deleting event to do this thing. In our case, we want to delete all related jobs if any particular customer is going to be deleted.
class Customer extends Model { public function jobs() { return $this->hasMany('\App\Models\Job'); } public static function boot() { parent::boot(); static::deleting(function($customer) { foreach ($customer->jobs as $job) { $job->delete(); } }); } }
Closure:
These tips and tricks will definitely help you overcome the time-consuming tendency by a high leap. Moreover, a developer should always be updated with the Laravel community. Unlike the old times, the community of Laravel has grown tremendously in size. Being helpful and supportive, the community members help newly-joined members and update them with the latest tips and tricks that not only make the work fun but evolve you as a more efficient developer as well.