Create a Laravel 8 Blog - Part 2: Scaffolding

Overview

Add MySQL tables

Posts and Comments

We're going to add migration files that create the MySQL tables.

./vendor/bin/sail artisan make:migration posts ./vendor/bin/sail artisan make:migration comments
# database/migrations/2021_06_23_155553_posts.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class Posts extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('posts', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id'); $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); $table->string('title')->unique(); $table->text('body'); $table->text('metaDescription'); $table->string('metaTitle'); $table->string('slug')->unique(); $table->boolean('active'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('posts'); } }
# database/migrations/2021_06_23_155557_comments.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class Comments extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('comments', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('post_id'); $table->unsignedBigInteger('user_id'); $table->foreign('post_id') ->references('id')->on('posts') ->onDelete('cascade'); $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); $table->text('comment'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('comments'); } }

See the commit

Users

Adjust the standard user migration to add a new columnn to track the user's role.

# database/migrations/2014_10_12_000000_create_users_table.php $table->enum('role',['admin','author','user'])->default('author');

See the commit

Run the Migrations

./vendor/bin/sail artisan migrate

Make the models

Make the Post and Comment model + adjust the User model to fetch the linked posts or comments.

./vendor/bin/sail artisan make:model Post ./vendor/bin/sail artisan make:model Comment
# app/Models/Post.php <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Post extends Model { use HasFactory; /** * Get the comments made on the post * * @return array App\Models\Comment */ public function comments() { return $this->hasMany('App\Models\Comment', 'post_id'); } /** * Get the user who created the post * * @return App\Models\User */ public function author() { return $this->belongsTo('App\Models\User', 'user_id'); } }
<?php # app/Models/Comment.php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Comment extends Model { use HasFactory; /** * The user who wrote the comment * * @return App\Models\User */ public function author() { return $this->belongsTo('App\Models\User', 'user_id'); } /** * The post the comment is associated with * * @return App\Models\Post */ public function post() { return $this->belongsTo('App\Models\Posts', 'post_id'); } }

Add these to the existing User model.

# app/Models/User.php public function posts() { return $this->hasMany('App\Models\Posts', 'user_id'); } public function comments() { return $this->hasMany('App\Models\Comments', 'user_id'); }

See commit 1

See commit 2

View/Layout

Add the base template to get a shared HTML structure started.

mkdir resources/views/layouts

Copy the welcome blade file and adjust it to include a @yield('content') where you want the content to show up and @yield('title') where you want the page title to show up.

cp resources/views/welcome.blade.php resources/views/layouts/app.blade.php

See the commit

Add Post controller, view, and route

./vendor/bin/sail artisan make:controller PostController mkdir resources/views/blog/

Add the PostController, it will fetch all active posts.

<?php # app/Http/Controllers/PostController.php namespace App\Http\Controllers; use Illuminate\Support\Str; use Illuminate\Http\Request; use App\Models\Post; class PostController extends Controller { public function index() { $posts = Post::where('active', 1) ->orderBy('created_at','desc') ->get(); //return blog.blade.php template from resources/views folder return view('blog.index', ['posts' => $posts, 'title' => 'Blog Posts']); } }
# resources/views/layouts/app.blade.php <!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ $title }}</title> </head> <body> @yield('content') </body> </html>
# resources/views/blog/index.blade.php @extends('layouts.app') @section('content') <h1>{{$title}}</h1> @forelse ($posts as $post) <li>{{ $post->title }}</li> @empty <p>No posts</p> @endforelse @stop

Add the route to send the URI /blog to the controller

# routes/web.php Route::get('/blog', 'App\Http\Controllers\PostController@index');

See commit 1

See commit 2

Test it out

Load the /blog path in the browser and confirm it works. http://localhost:6001/blog. You should see the title of Blog Posts and No posts because we haven't added anything yet.

No posts image

Roundup

That's it for now. Part 3 will go through setting up a login mechanism and handling authorization.

Next: Authorization/Login

If you have any feedback for me, I'd love to hear it - corrections, alternative paths, you name it! Send me an email levi@levijackson.xyz