In this tutorial we will see how to add tags in posts using many to many relationships.
Create Post Modal Migration Controller and Route
run below command to create post modal, migration and controller.
php artisan make:model Post -mcr
create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug');
$table->longText('description');
$table->timestamps();
});
}
Create Tags Modal and Migration
php artisan make:model Tag -m
create_tags_table.php
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
Create Post Tag Pivot Table
Run below command to create post tag pivot table.
php artisan make:migration CreatePostTagTable
post_tag_table.php
public function up()
{
Schema::create('post_tag', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->foreignId('tag_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
web.php
Route::resource('posts', PostController::class);
Create Tags Seeder
php artisan make:seeder TagSeeder
seeders/TagSeeder.php
<?php
namespace Database\Seeders;
use App\Models\Tag;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class TagSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$data = [
[
'name' => 'Laravel',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Node JS',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Python',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Java',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'React',
'created_at' => now(),
'updated_at' => now()
],
];
Tag::insert($data);
}
}
seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(TagSeeder::class);
$this->command->info('Tag Seeder created.');
}
}
Add Tag Many to Many Relationships in Modal
Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'description',
];
public function tags()
{
return $this->belongsToMany(Tag::class)->as('tags');
}
}
Models/Tag.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function posts()
{
return $this->belongsToMany(Post::class);
}
}
Attach Tags in Post Controller
Attach Tags in PostController.php using many to many relationships.
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::with(['tags'])->latest()->paginate(10);
return view('posts.index', compact('posts'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$tags = Tag::all();
return view('posts.create', compact('tags'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'slug' => 'required|string|max:255',
'description' => 'required'
]);
$post = Post::create([
'title' => $request->title,
'slug' => \Str::slug($request->slug),
'description' => $request->description,
]);
if ($request->has('tags')) {
$post->tags()->attach($request->tags);
}
return redirect()->route('posts.index')->with('status', 'Post Created Successfully');
}
}
Add Tags in Blade File
views/posts/create.blade.php
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Title</span>
<input type="text" name="title"
class="block w-full @error('title') border-red-500 @enderror mt-1 rounded-md" placeholder=""
value="{{old('title')}}" />
</label>
@error('title')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Slug</span>
<input type="text" name="slug" class="block w-full @error('slug') border-red-500 @enderror mt-1 rounded-md"
placeholder="" value="{{old('slug')}}" />
</label>
@error('slug')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Tag</span>
<select name="tags[]" class="block w-full mt-1" multiple>
@foreach ($tags as $tag)
<option value="{{ $tag->id }}">{{ $tag->name }}</option>
@endforeach
</select>
</label>
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Description</span>
<textarea " class="block w-full mt-1 rounded-md " name="description"
rows="3">{{old('description')}}</textarea>
</label>
@error('description')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="text-white bg-blue-600 rounded text-sm px-5 py-2.5">Submit</button>
</form>
Show Posts Tags
views/posts/index.blade.php
<table class="w-full text-sm text-left text-gray-500">
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3">
#
</th>
<th scope="col" class="px-6 py-3">
Name
</th>
<th scope="col" class="px-6 py-3">
Tags
</th>
</tr>
</thead>
<tbody>
@foreach ($posts as $post)
<tr class="bg-white border-b">
<th scope="row" class="px-6 py-4 font-medium text-gray-900">
{{ $post->id }}
</th>
<td class="px-6 py-4">
{{ $post->title }}
</td>
<td class="px-6 py-4">
@foreach ($post->tags as $tag)
{{ $tag->name }}
@endforeach
</td>
</tr>
@endforeach
</tbody>
</table>