This post will highlight all the essentials bare bone coding of laravel implementation of mini blog from migrations, models, relations, controllers, routes to view files.
Suppose there will be following tables for this blog project.
1. users
2. articles
3. categories
4. tags
5. article_category
6. article_tag
then if we aim for migration schema of above tablesĀ following snippets would need to be implemented
1. user
public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('email')->unique(); $table->string('password'); $table->rememberToken(); $table->timestamps(); $table->softDeletes(); }); }
2. articles
public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->foreignId('user_id')->constrained(); $table->string('title'); $table->text('article_text'); $table->timestamps(); $table->softDeletes(); }); }
3. categories
public function up() { Schema::create('categories', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); $table->softDeletes(); }); }
4. tags
public function up() { Schema::create('tags', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); $table->softDeletes(); }); }
5. article_category ( pivot table )
public function up() { Schema::create('article_category', function (Blueprint $table) { $table->id(); $table->foreignId('article_id')->constrained(); $table->foreignId('category_id')->constrained(); $table->timestamps(); $table->softDeletes(); }); }
6. article_tag ( pivot table )
public function up() { Schema::create('article_tag', function (Blueprint $table) { $table->id(); $table->foreignId('article_id')->constrained(); $table->foreignId('tag_id')->constrained(); $table->timestamps(); $table->softDeletes(); }); }
After migration here are quick snippets for setting up relationship among these tables in respective model files
1. Article.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Article extends Model { use SoftDeletes; protected $fillable = ['user_id', 'title', 'article_text']; public function author() { return $this->belongsTo(User::class); } public function categories() { return $this->belongsToMany(Category::class); } public function tags() { return $this->belongsToMany(Tag::class); } public function getCategoriesLinksAttribute() { $categories = $this->categories()->get()->map(function($category) { return '.route('articles.index').'?category_id='.$category->id.'">'.$category->name.''; })->implode(' | '); if ($categories == '') return 'none'; return $categories; } public function getTagsLinksAttribute() { $tags = $this->tags()->get()->map(function($tag) { return '.route('articles.index').'?tag_id='.$tag->id.'">'.$tag->name.''; })->implode(' | '); if ($tags == '') return 'none'; return $tags; } }
2. Category.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Category extends Model { use SoftDeletes; protected $fillable = ['name']; public function articles() { return $this->belongsToMany(Article::class); } } ?>
3. Tag.php
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; class Tag extends Model { use SoftDeletes; protected $fillable = ['name']; public function articles() { return $this->belongsToMany(Article::class); } }
After setting up relationship its time to give focus on controller particularly on ArticleController.php with following methods
for listing, creating and showing articles in blade views
public function index() { $articles = Article::with(['categories', 'tags', 'author']) ->orderBy('id', 'desc') ->paginate(3); $all_categories = Category::all(); $all_tags = Tag::all(); return view('articles.index', compact('articles', 'all_categories', 'all_tags')); } public function create() { $categories = Category::orderBy('name')->get(); return view('articles.create', compact('categories')); } public function store(StoreArticleRequest $request) { $article = Article::create($request->all() + ['user_id' => auth()->id()]); if (isset($request->categories)) { $article->categories()->attach($request->categories); } if ($request->tags != '') { $tags = explode(',', $request->tags); foreach ($tags as $tag_name) { $tag = Tag::firstOrCreate(['name' => $tag_name]); $article->tags()->attach($tag); } } return redirect()->route('articles.index'); } public function show(Article $article) { $article->load(['categories', 'tags', 'author']); $all_categories = Category::all(); $all_tags = Tag::all(); return view('articles.show', compact('article', 'all_categories', 'all_tags')); }
After controller lets give focus on views index.blade.php, create.blade.php and show.blade.php respectively
1. index.blade.php
@forelse ($articles as $article) <a href="{{ route('articles.show', $article->id) }}"><h2>{{ $article->title }}</h2></a> <b>Author:</b> {{ $article->author->name }} <b>Categories:</b>{!! $article->categories_links !!} // this customly built model attribute created in Article.php model with laravel accessor method getCategoriesLinksAttribute() <b>Tags:</b>{!! $article->tags_links !!} // this is also customly built model attribute created in Article.php model with laravel accessor method getTagsLinksAttribute() <p>{{ substr($article->article_text, 0, 200) }}...<a href="{{ route('articles.show', $article->id) }}">Read full article</a></p> @empty No articles yet. @endforelse
2. create.blade.php
@if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif Categories: <br /> @foreach ($categories as $category) <input type="checkbox" name="categories[]" value="{{ $category->id }}" /> {{ $category->name }} <br /> @endforeach Tags (comma-separated): <input type="text" name="tags" class="form-control" /> <br />
3. show.blade.php
<b>Author:</b> {{ $article->author->name }}
<b>Categories:</b>{!! $article->categories_links !!} // this customly built model attribute created in Article.php model with laravel accessor method getCategoriesLinksAttribute()
<b>Tags:</b>{!! $article->tags_links !!} // this is also customly built model attribute created in Article.php model with laravel accessor method getTagsLinksAttribute()
<p>{!! nl2br($article->article_text) !!}</p>
?>
Lastly, setting up routes for ArticleContoller.php
Route::resource('articles', \App\Http\Controllers\ArticleController::class);
For advanced step if we need to search articles with category, tag or text we can modify the index() method of ArticleController.php like below
public function index() { $articles = Article::with(['categories', 'tags', 'author']) ->when(request('category_id'), function($query) { return $query->whereHas('categories', function($q) { return $q->where('id', request('category_id')); }); }) ->when(request('tag_id'), function($query) { return $query->whereHas('tags', function($q) { return $q->where('id', request('tag_id')); }); }) ->when(request('query'), function($query) { return $query->where('title', 'like', '%'.request('query').'%'); }) ->orderBy('id', 'desc') ->paginate(3); $all_categories = Category::all(); $all_tags = Tag::all(); return view('articles.index', compact('articles', 'all_categories', 'all_tags')); }
Above eloquent when() method is used instead of if else for checking query string existence and querying Article model.