Database and Eloquent ORM: New features and improvements since the original Laravel 8 release (2/2)
This blog post follows up on last week's overview of the new Database and Eloquent features in Laravel 8 since the original release in September 2020. I already covered Collections, and next week is all about Jobs and Queues. Enjoy!
I got most code examples and explanations from the PRs and official documentation.
v8.41.0 Added Model::updateQuietly() (#37169)
Sometimes you may wish to "update" a given model without dispatching any events. You may accomplish this using the updateQuietly
method, which uses the saveQuietly
method under the hood:
$flight->updateQuietly(['departed' => false]);
As of v8.59, you may also use the createOneQuietly
, createManyQuietly
and createQuietly
methods when using Model Factories:
Post::factory()->createOneQuietly(); Post::factory()->count(3)->createQuietly(); Post::factory()->createManyQuietly([ ['message' => 'A new comment'], ['message' => 'Another new comment'],]);
v8.41.0 Added Model key extraction to id on whereKey() and whereKeyNot() (#37184)
You can now use a Model instance with the whereKey
and whereKeyNot
methods:
$passenger->tickets() ->whereHas('airline', fn (Builder $query) => $query->whereKey($airline)) ->get();
v8.42.0 Added withExists method to QueriesRelationships (#37302)
In addition to the withCount
method, you may now use the withExists
method to check the existence of a relationship:
// before:$users = User::withCount('posts')->get(); $isAuthor = $user->posts_count > 0; // after:$users = User::withExists('posts')->get(); $isAuthor = $user->posts_exists; // the column name can also be aliased:$users = User::withExists([ 'posts as is_author', 'posts as is_tech_author' => function ($query) { return $query->where('category', 'tech'); }, 'comments',])->get();
v8.42.0 Added loadExists on Model and Eloquent Collection (#37388)
This PR follows upon the withExists
method in the example above. You may now use the loadExists
method in both Model and Eloquent Collections:
$books = Book::all(); $books->loadExists(['author', 'publisher']);
v8.42.0 Added one-of-many relationship (inner join) (#37362)
One-to-one relations that are a partial relation of a one-to-many relation. You can retrieve the "latest" or "oldest" related model of the relationship:
/** * Get the user's most recent order. */public function latestOrder(){ return $this->hasOne(Order::class)->latestOfMany();} /** * Get the user's oldest order. */public function oldestOrder(){ return $this->hasOne(Order::class)->oldestOfMany();} /** * Get the user's largest order. */public function largestOrder(){ return $this->hasOne(Order::class)->ofMany('price', 'max');}
v8.43.0 Added eloquent strict loading mode (#37363)
You may instruct Laravel to always prevent the lazy loading of relationships. You should call this method within the boot
method of your app's AppServiceProvider
class.
Model::preventLazyLoading(! app()->isProduction());
v8.43.0 Added beforeQuery to base query builder (#37431)
This PR is a very advanced one! It allows you to change a "subselect"-builder, whereby the changes are also applied to the parent query builder. The preserved closures will be called before the query gets rendered. This way, you can keep "subquery"-builders alive and modify the subquery after applying it to the parent builder:
// 1. Add the subquery$builder->beforeQuery(function ($query) use ($subQuery) { $query->joinSub($subQuery, ...);}); // 2. Add constraints to the subquery$subQuery->where('foo', 'bar'); // 3. Render the subquery, the constraints from 2. are applied$builder->get();
v8.50.0 Added the possibility of having "Prunable" models (#37889)
You may want to periodically delete models that are no longer needed. With the Prunable
trait Laravel will automatically remove obsolete model records from the database via a scheduled command.
use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Prunable; class Flight extends Model{ use Prunable; /** * Get the prunable model query. * * @return \Illuminate\Database\Eloquent\Builder */ public function prunable() { return static::where('created_at', '<=', now()->subMonth()); }}
The Artisan CLI command:
php artisan model:prune
You may also define a pruning
method on the model, which will be called before the model is deleted:
protected function pruning(){ // Delete additional resources associated // with the model, for example: files Storage::disk('s3')->delete($this->filename);}
v8.53.0 Added immutable date and datetime casting (#38199)
Ssupport for accessing dates as immutable. Returns a CarbonImmutable
instance instead of a Carbon
instance.
class User extends Model{ public $casts = [ 'date_field' => 'immutable_date', 'datetime_field' => 'immutable_datetime', ];}
v8.57.0 Added a simple where helper for querying relations (#38499)
You may now use the whereRelation
and whereMorphRelation
methods to query for a relationship's existence with a single, simple where condition attached to the relationship query:
// Before:User::whereHas('posts', function ($query) { $query->where('published_at', '>', now());})->get(); // AfterUser::whereRelation('posts', 'published_at', '>', now())->get(); // Morph relationComment::whereMorphRelation('commentable', '*', 'public', true);
v8.59.0 Added Eloquent builder whereMorphedTo method to streamline finding models morphed to another model (#38668)
The new whereMorphedTo
and orWhereMorphedTo
methods are a shortcut for adding a where condition looking for models that are morphed to a specific related model, without the overhead of a whereHas
subquery:
Feedback::whereMorphedTo('subject', $user)->get(); Feedback::whereMorphedTo('subject', User::class)->get();
v8.59.0 Added support for disallowing class morphs (#38656)
You may call the enforceMorphMap
method in the boot method of your apps' AppServiceProvider
class. This disallows morphs without a morph map on it.
use Illuminate\Database\Eloquent\Relations\Relation; Relation::enforceMorphMap([ 'post' => Post::class, 'video' => Video::class,]);
v8.60.0 Added the valueOfFail() Eloquent builder method (#38707)
In addition to the value
method, you may now use the valueOrFail
method. This will throw a ModelNotFoundException
if the model is not found.
// Before:$votes = User::where('name', 'John')->firstOrFail('votes')->votes; // Now:$votes = User::where('name', 'John')->valueOrFail('votes');
v8.63.0 Added whereBelongsTo() Eloquent builder method (#38927)
The new whereBelongsTo
method automatically determines the proper relationship and foreign key for the given model:
// Before:$posts = Post::where('user_id', $user->id)->get(); // After:$posts = Post::whereBelongsTo($user)->get();