Search code examples
laravelmany-to-manypivot

2 models with pivot table, many to many relationship


I'm trying to create a blog and I have two models, Post and Tag. I want to connect both of them with a pivot table. It's a many to many relationship and I can't figure out how to link posts and tags together. when I try to do that, it returns nothing on my DB. Posts have a title and the content while tags only have the name. I've read I have to use the sync method or attach-detach but I don't know where to do that. Is it on posts routes or tags routes? I have included the routes of posts and tags on routes.php grouping them by using:

Route::resource('/tags', 'TagController');

Route::resource('/posts', 'PostController');

Here's what i have so far:

My Post model:

class Post extends Model{
protected $fillable = [
    'title', 'content'
];

protected $hidden = [
    'view_count'
];

public function tags()
{
    return $this->belongsToMany('App\Tag', 'post_tag');
}}

Here is my Tag model:

class Tag extends Model{
protected $fillable = [
    'name'
];

public function posts(){
    return $this->belongsToMany('App\Post', 'post_tag');
}}

Here's my post_tag pivot table:

class CreatePostTagTable extends Migration{

public function up()
{
    Schema::create('post_tag', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('post_id')->unsigned()->nullable()->index();
        $table->foreign('post_id')->references('id')->on('posts');
        $table->integer('tag_id')->unsigned()->nullable()->index();
        $table->foreign('tag_id')->references('id')->on('tags');
        $table->timestamps();
    });
}

public function down()
{
    Schema::dropIfExists('post_tag');
}}

Solution

  • Hey there I was new too in laravel, and I have same problem with you. In your case I think the best practice is attach it in your PostController.php. Let me share the code for you, and I hope it can help

    PostController

    public function store (Request $request) {
    
        // First we need to create variable that contain your tag_id
        // $tags = [1, 2, 4]; something like this
        $tags = $request->input('tags');
    
    
    
        // Now storing the data in posts table
        $post =  new Post;
        $post->title = $request->input('title');
        $post->content = $request->input('content');
        $post->save();
    
        //After save the post, we need to attach it
        $post->tags()->attach($tags);
    }
    

    Edit: Add example view

    <div>
        <input type="checkbox" id="subscribeNews" name="tags[]" value="1">
        <label for="subscribeNews">Tag 1</label>
        <input type="checkbox" id="subscribeNews" name="tags[]" value="2">
        <label for="subscribeNews">Tag 2</label>
        <input type="checkbox" id="subscribeNews" name="tags[]" value="3">
        <label for="subscribeNews">Tag 3</label>
        <input type="checkbox" id="subscribeNews" name="tags[]" value="n">
        <label for="subscribeNews">More tag</label>
      </div>

    And then in PostController.php you can get the id if user check the checkbox:

    $tags = $request->input('tags');
    

    Edit2: Add example use sync

    Here, I give you little example on using sync, first let's set a post that have 5 tags on it. And in the end we just want to set it 3

    $post = Post::find(1) //get the post with id 1, this post have 5 tags
    // Let's say that this post have 5 tags with this ids [1, 2, 3, 4, 5]
    
    // And then admin edit this post and select the tag with id [1, 2, 6] we set it in $tags variable
    $tags = $request->input('tags'); //[1, 2, 6]
    
    // And the last we just need to use sync method like this
    $post->tags()->sync($tags);
    
    // After use that, it will detach the tag based from removed ids [3, 4, 5] and attach new tag if there's new tag id [6]
    // And in the end the post just have 3 tags
    

    Okay that is example logic, I still learn about it too, but I hope it can help you :D