Watch Video:
Lazy Loading
If additional constraints to an Eloquent relationship query are not needed at first, we can simply access the relationship as if it were a property of that model. Like in here we have a Post model and it belongs to only one Category. To get the category we can simply access it in the blade templet. Because we access it later, not the time of the posts query it’s called Lazy loading.
$posts = Post::all();
Access later
@foreach ($posts as $post)
{{$post->title}}
{{$post->category->name}}
@endforeach
The process will loop all records in houses and execute 1 query for each loop to get the city data, for example that we have 5 records of posts, the query to get the data in the relationship table will execute 5 times + 1 original query for getting the house data, the time of query for “Lazy loaded” is N+1.
Eager Loading
Eager loading initializes or loads a resource as soon as the code is executed. However, Eloquent can “eager load” relationships at the time you query the parent model. Eager loading solved the N + 1 query problem and it is very usefull when we make API and send additional relationship data. Because the API sends data as JSON, we cannot use php there. So eager loading is the only way to do this.
$posts = Post::with(‘category’)->get();
When we access later it solved n+1 problem:
@foreach ($posts as $post)
{{$post->title}}
{{$post->category->name}}
@endforeach
We can see our queries have been reduced from 6 to 2. First server loads the posts then loads all categories for the post's ids in the next query.
Lazy load and Eager load in Laravel
1. Project Setup
For this tutorial, we will be using the same app which we build in the previous tutorial (post link).
We create some posts with category.
Database/migrations
Posts migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('category_id')->nullable();
$table->text('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
Category migration -
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('about');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
Post Model -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
// protected $guarded = [];
protected $fillable = ['title', 'body'];
public function category(){
return $this->belongsTo('App\Models\Category');
}
}
Category Model -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
public function posts(){
return $this->hasMany('App\Models\Post');
}
}
PostController -
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class PostController extends Controller
{
public function index()
{
$posts = Post::all();
// return response($posts,200);
return view('posts.index', compact('posts'));
}
}
Posts View
index.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
body {
font-family: 'Nunito', sans-serif;
}
</style>
</head>
<body>
<div class="container">
<div class="row my-5">
<div class="col p-2">
<h1>Posts</h1>
</div>
</div>
<div class="row d-flex justify-content-center">
<div class="col-12">
@foreach ($posts as $post)
<div class="card my-2">
<div class="card-body">
<h2 class="text-dark">{{$post->title}}</h2>
<h4 class="text-success"><b>{{$post->category->name}}</b></h4>
<div class="card-text">{{$post->body}}</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
{{-- JS --}}
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
2. Eager Loading in Laravel 8
We can eager load from Controller and if you want to eager load by default define it on Model.
Setup in Controller
public function index()
{
$posts = Post::with('category:id,name')->get();
return view('post.index',compact('posts'));
// return response($posts);
}
Use with(‘category’) method to load relationship data. You can specify the attribute of that relationship data with(‘category:id,name’). Remember id is mandatory when define attributes.
Setup in Model
You can setup it also in Model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
// protected $guarded = [];
protected $fillable = ['title', 'body'];
protected $with = ['category:id,name'];
public function category(){
return $this->belongsTo('App\Models\Category');
}
}
If you do the same with the category model Don’t forget to define the attributes you want to eager load (Explain) in the video.
Do not forget to like and share this post.
⭐GitHub Repository: https://github.com/subhadipghorui/laravel-advanced-topics
0 Comments