Laravel-mysql-one-to-many-relationship.
To understand one to many relationship we need two example tables ,
let take two table named blog_posts and comments.
now we will make necessary columns for blog_posts table
Schema::create('blog_posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content')->nullable();
$table->timestamps();
});
and comments table
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('content');
$table->unsignedBigInteger('blog_post_id')->index() ;
$table->foreign('blog_post_id')->references('id')->on('blog_posts')->onUpdate('cascade')->onDelete('cascade') ;
$table->timestamps();
});
now we will establish a connection or relationship between blog_post and comments table with foreign() method that will grab our column named 'blog_post_id' and assign the targeted values inside this grabbed field , refferences() method will target id value of 'blog_posts' table which is targeted using on() methos
from right to left , we can simply say that on('blog_posts') table take the value of column references('id') and set it to our foreign('blog_post_id') field in comments table.
foreign('current_table_column_name')->refferences('targeted_table_column_name')->on('targeted_table')->onUpdate('cascade')->onDelete('cascade')
onUpdate('cascade') and onDelete('cascade') will take action automatically if foreign_table row is updated or deleted .
Link up with blog_posts and comments is done , now we should set method in BlogPost Model to access comments table data.
To set type of relationship between BlogPost and Comment.
class BlogPost extends Model
{
use HasFactory;
public $timestamps = true ;
protected $fillable = [// enabling to assign values in these fields using $fillable
'title',
'content'
];
/// defining our comments() method and saying that one BlogPost has many Comment
public function comments(){
return $this->hasMany(Comment::class) ;
}
}
class Comment extends Model
{
use HasFactory;
protected $fillable = [
'content'
];
// in our comments table we defining relational column id named
// blog_post_id now wen must name our method "blog_post()"
// if we define relational column id with "abdx_blog_table_id" then
// method named will must be "abdx_blog_table()"
// here is another example if post_id
// public function then->post(){
// return $this->belongsTo(BlogPost::class) ;
// }
//blog_post_id
public function blog_post(){
return $this->belongsTo(BlogPost::class) ;
}
}
now we will run php artisan tinker command to run command shell in laravel
we will add a blog post using tinker example code is here
$bp = BlogPost::create([ . "title" => "title-1", . "content" => "content-1" . ]);
$bp = BlogPost::create([ . 'title' => 'title-2', . 'content' => 'content-2' . ])
$bp = BlogPost::find(5) //find by id
creating two posts and selecting post which id number is 5
run php artisan tinker
$bp = BlogPost::find(5) //finding post number 5
$comment = new Comment() //creating a instance for Comment model
$comment->content = 'comment-1' //adding data to comment instance
$bp->comments()->save($comment) // assigning comment instance to
//$bp which is Blog Post with id 5
now we will see that our comment table has a new filled row with value in content and blog_post_id another example
$bp = BlogPost::find(6)
$comment = new Comment()
$comment->content = 'content-2'
$bp->comments()->save($comment)
now we tried these commands
$bp = BlogPost::find(6)
$comment = new Comment()
$comment->blog_post()->save($bp)
then we will get a error message
"BadMethodCallException Call to undefined method Illuminate\Database\Eloquent\Relations\BelongsTo::save()."
now we run
$comment->blog_post()->associate($bp)->save()
to save comment with $bp
another way save $bp in comment table
$comment = new Comment()
$comment->content = "third comment"
$comment->blog_post_id = 5
$comment->save()
$comment = new Comment()
$comment->content = 'a'
$comment2 = new Comment()
$comment2->content = 'b'
$bp = BlogPost::find(5)
$bp->comments()->saveMany([$comment,$comment2])
Query one to many relationship
$post = BlogPost::with('comments')->get()
$post = BlogPost::all()
$bp = BlogPost::find(5)
$bp->comments
$comment = Comment::find(10)
$comment->blog_post
$comment
eager loading
eager loading with withCount , here withCount will create a new field named ''comments_count" with number of comment in each blog post.
$posts = BlogPost::withCount('comments')->get();
$posts = BlogPost::with('comments')->get();
this query will return all BlogPost with comments so query will efficient with eager loading
lazy loading
example for a lazy loading
$posts = BlogPost::all() ;