Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add Tags to Laravel Built Blog

I built a blog with Laravel, but I haven't figured out how to add tags to it. I would like to avoid using packages. Here is the code I have so far:

TagsController -

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Tag;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Session;

class TagsController extends Controller
{
public function index() {
    $tags = Tags::paginate(4); 
    return view('dashboard/tags/index', compact('tags'));

}

public function create() {
    return view('dashboard/tags/create');
}

public function store() {
    $tags = new Tags;

    $tags->name= $request->input('name');
    $tags->save();
    Session::flash('flash_message', 'Tag successfully added!');
    return Redirect('/dashboard/tags');
}
}

Tag Model

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
public function posts()
{
    return $this->belongsToMany('App\Post');
}
}

I'm not sure how to add more than one tag, so I can put it on the posts.

I'm on Laravel 5.3.

like image 417
Judia Avatar asked Dec 10 '16 05:12

Judia


1 Answers

A post can have multiple/many tags and a tag can be shared by multiple/many posts. Which basically means that there is a Many-To-Many relationship between Post and Tag.

To define a many-to-many relation you will need 3 database tables

  1. posts
  2. tags
  3. post_tag

post_tag will have post_id and tag_id with migration as

class CreatePostTagPivotTable extends Migration 
{

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post_tag', function(Blueprint $table)
        {
            $table->integer('post_id')->unsigned()->index();
            $table->foreign('post_id')->references('id')->on('posts')->onUpdate('cascade')->onDelete('cascade');
            $table->integer('tag_id')->unsigned()->index();
            $table->foreign('tag_id')->references('id')->on('tags')->onUpdate('cascade')->onDelete('cascade');            
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('post_tag');
    }

}  

The you can define the relationship in respective models as

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    public function posts()
    {
        return $this->belongsToMany('App\Post');
    }
}


namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function tags()
    {
        return $this->belongsToMany('App\Tag');
    }
}  

Then you can access the relation, like you normally do $tag->with('posts')->get(); to get all posts associated with a tag and so on.

By the way there's a typo in your controller code new Tags it should be $tag = new Tag;. The model name that you have is Tag.

Hope this helps.

Then in your create-post form you could have an input filed like

<input type="text" name="tags" class="form-control"/>
//here you can input ','(comma)separated tag names you want to associate with the post  

And in your PostsController

public function store(Request $request)
{
    $post = Post::create([
        'title' => $request->get('title'),
        'body'  => $request->get('body')
    }); 

    if($post)
    {        
        $tagNames = explode(',',$request->get('tags'));
        $tagIds = [];
        foreach($tagNames as $tagName)
        {
            //$post->tags()->create(['name'=>$tagName]);
            //Or to take care of avoiding duplication of Tag
            //you could substitute the above line as
            $tag = App\Tag::firstOrCreate(['name'=>$tagName]);
            if($tag)
            {
              $tagIds[] = $tag->id;
            }

        }
        $post->tags()->sync($tagIds);
    }
}
like image 154
Donkarnash Avatar answered Oct 14 '22 14:10

Donkarnash