Insert and attach tag to the post in same time

Posted on

Problem

I created a form with title, body and tag input and there are 3 tables: posts, tags and post_tag.

Now I use this function to add new tags and attach them to the post

postcontroller.php

 public function store(Request $request)
    {
        $input = $request->all(); //get inputs value

        $tag = $input['tag'];
        $tagdone = Tag::create(['name'=>$tag]);
        $tagid = $tagdone->id; //insert tag to tags table

        $posts = Posts::create($input); //insert posts table
        $postid = $posts->id; 

        Posts::find($postid)->tags()->attach($tagid); //attach tag to the post
    }

There are actually 3 actions at the same time. But I think there are better ways than this one, so I’d like some feedback on what I’ve written.

Solution

Use the following:

 public function store(Request $request)
    {
        $input = $request->all(); //get inputs value

        $tag = $input['tag'];
        $tagdone = Tag::create(['name'=>$tag]);
        $tagid = $tagdone->id; //insert tag to tags table

        $posts = Posts::create($input); //insert posts table

        $posts->tags()->attach($tagid); //attach tag to the post
    }

This will reduce your database queries by one SELECT by removing Posts::find($postid).


Apart from the above, is there any reason for using three database tables? Just from the code provided it doesn’t seem to be necessary and I would only use one table with all three inputs. Or at least reduce to two database tables as follows:

 public function store(Request $request)
    {
        $input = $request->all(); //get inputs value

        $tag = $input['tag'];
        $tagdone = Tag::create(['name'=>$tag]); //insert tag to tags table

        $input['tagid'] = $tagdone->id;

        $posts = Posts::create($input); //insert posts table, including tagid
    }

First, a very small thing: it would me somewhat more convention to name your model Post instead of Posts. If you are attached to Posts, then Tag should also be plural.

Currently, it appears that you create a new Tag each time, even if you already have a Tag by the same name. This could be what you want, but in case it isn’t, try changing:

$tagdone = Tag::create([‘name’=>$tag]); //insert tag to tags table

to

$tagdone = Tag::findOrCreate(['name'=>$tag]); //insert tag to tags table

Now, assuming you do want to create a new Post every time the form is submitted, you can use the relationships you define in your models to do more work for you.

Bringing together a few ideas:

public function store(Request $request)
{
    $input = $request->all();

    $post = Post::create($input);
    $tag = Tag::findOrCreate(['name' => $input['tag']);

    $post->tags()->attach($tag->id);
}

On a style note, you don’t need comments when you are doing normal things, they just make it harder to read the code. Comments should explain why you’ve done something unusual or why a future coder needs to be careful.

It looks like you’re off to a great start with Laravel! Hope your project is a success!

Leave a Reply

Your email address will not be published. Required fields are marked *