Laravel 8: Basic CRUD Blog Tutorial with Bootstrap

By Parth Patel on Oct 09, 2020

In the previous tutorial, we learned how to setup authentication in Laravel 8 using Bootstrap. In this article, we will build on top of that.

We will create basic CRUD web application — CRUD means Create, Read, Update, & Delete. Thus, we will learn how to do these operations in Laravel 8.

Note: I am not explaining how to install and start project here since this article is sequel to previous post. If you are new here, please start from Laravel 8 Authentication using Bootstrap 4

Also Read: Laravel Tutorial for Beginners

Since, we already have Laravel project with authentication in place, let's create a Blog !

Step 1): Create Database Table

First of all, we will need to create additional database table to store our blog posts. Right? Let's get on it!

php artisan make:migration create_posts_table --create=posts

This will create migration for creating posts table for you. We just need to update it to add columns we need, so modify the file as below:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->datetime('published_at')->nullable();
            $table->timestamps();
        });
    }

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

Now, run the migration to create the table:

php artisan migrate

Step 2): Create Post Model

Model is a class which maps to database table and represent domain-specific data and business logic.

If it's confusing to you, simply ignore for now, you will understand it more clealy practically.

Let's create Post Model for now:

php artisan make:model Post

It will create the Post model file in app/Models folder.

Now, normally you would have to define which database table it should map to, but Laravel follows specific convention by default and thus, by default it will try to map to model's name in plural form —> i.e posts table in our case

Laravel Model has some data protections in place among which one field is $fillable property. $fillable property defines which properties in the model object are fillable via mass assignment. Other fields even if passed via mass assignment will be ignored. So, for our case, let's enable some fields as fillable.

Step 3): Add Routes for CRUD

Route file is a file where you will register web routes for your application. We will add new routes for CRUD operations for our blog.

Updates routes in routes/web.php as shown below:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', [App\Http\Controllers\PostController::class, 'index'])->name('home');
Route::get('post/create', [App\Http\Controllers\PostController::class, 'create']);
Route::post('post', [App\Http\Controllers\PostController::class, 'store']);
Route::get('post/{post}/edit', [App\Http\Controllers\PostController::class, 'edit']);
Route::get('post/{post}', [App\Http\Controllers\PostController::class, 'show']);
Route::put('post/{post}', [App\Http\Controllers\PostController::class, 'update']);
Route::delete('post/{post}', [App\Http\Controllers\PostController::class, 'destroy']);

Let's about these new added routes.

First of all, I have replaced controller for /home route. So that, if we go to "/home" route, the request should be handled by PostController's index method. At /home page, we want to show list of posts.

Note: get, post, put, delete are types of requests → Post is generally used to pass data securely in forms. Put and Delete are types of Post requests, where Put is used when you want to update something while Delete is used when you want to delete something.

We have used {post} in the route path for some routes. Did you notice? That is a wonderful feature by laravel called Route Model Binding. In very short, when we pass id via route path, (ex: example.com/post/2), in related controller method, Laravel can automatically bind the request to Model object, in our case, we will have direct access to $post (Post object with id 2).

Step 4): Create CRUD Controller for Posts

Controller is a class which will contain logic for how to handle incoming requests and determines what to do with them, as well as which view to use.

We will need a controller for posts to handle its CRUD requests and operations. So, let's create a controller:

php artisan make:controller PostController

It will create PostController class file in app/Http/Controllers folder.

Now, let's create some methods we need from our routes file:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }

    public function create()
    {
        return view('posts.create');
    }

    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required',
            'body' => 'required',
            ]);
        $post = new Post();
        $post->title = $request->title;
        $post->body = $request->body;
        $post->published_at = $request->published_at;

        $post->save();
        return redirect('/home')->with('success','Post created successfully!');
    }

    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }

    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    public function update(Post $post, Request $request)
    {
        $request->validate([
            'title' => 'required',
            'body' => 'required',
            ]);
        $post->title = $request->title;
        $post->body = $request->body;
        $post->published_at = $request->published_at;

        $post->save();
        return redirect('/home')->with('success','Post updated successfully!');
    }

    public function destroy(Post $post)
    {
        $post->delete();
        return redirect('/home')->with('success','Post deleted successfully!');
    }
}

I know there is lot of code above! Let's talk about it.

So, basically I have created separate methods to handle different types of request in our CRUD operations.

1) index() → This will pass the variable with list of all posts to the view file - resources/views/posts/index.blade.php

2) create() → This will simply show the create post form view file - resources/views/posts/create.blade.php

3) store() → This method will receive $request data from the route and will create new Post record using that data

4) show() → This method will pass Post data obtained via Route-Model Binding to the view file to display post

5) edit() → This method will pass Post data to the edit post form page.

6) update() → This method will receive Post data and $request data and will update Post accordingly

7) destroy() → This method will delete Post

Step 5): Create Blade View files

Now, last thing we need is to create Blade view files. View files are just the UI files responsible for displaying page as per the requirement. It can receive data from controller method and can use it while displaying the page.

I am not going to explain the code below since it is self-explanatory but in case, you don't understand anything, you can comment below or contact me via email.

Let's create view files and add code as below:

1) Index page

Create index.blade.php file at resources/views/posts folder (You also need to create posts folder btw 😜) and copy code as below:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
    <div class="col-12">
                <a href="posts/create" class="btn btn-primary mb-2">Create Post</a> 
                <br>
                <table class="table table-bordered">
                    <thead>
                        <tr>
                            <th>Id</th>
                            <th>Title</th>
                            <th>Published At</th>
                            <th>Created at</th>
                            <th colspan="2">Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach($posts as $post)
                        <tr>
                            <td>{{ $post->id }}</td>
                            <td>{{ $post->title }}</td>
                            <td>{{ date('Y-m-d', strtotime($post->published_at)) }}</td>
                            <td>{{ date('Y-m-d', strtotime($post->created_at)) }}</td>
                            <td>
                            <a href="posts/{{$post->id}}" class="btn btn-primary">Show</a>
                            <a href="posts/{{$post->id}}/edit" class="btn btn-primary">Edit</a>
                            <form action="posts/{{$post->id}}" method="post" class="d-inline">
                                {{ csrf_field() }}
                                @method('DELETE')
                                <button class="btn btn-danger" type="submit">Delete</button>
                            </form>
                            </td>
                        </tr>
                        @endforeach
                    </tbody>
                </table>
            </div> 
    </div>
</div>
@endsection

2) Create Page

Create create.blade.php file at resources/views/posts folder and paste below code:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Create Post') }}</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif
                    
                    <form action="/post" method="post">
                        @csrf
                        <div class="form-group">
                            <label for="">Post Title</label>
                            <input type="text" name="title" class="form-control">
                        </div>

                        <div class="form-group">
                            <label for="">Post Body</label>
                            <textarea name="body" id="" cols="30" rows="10" class="form-control"></textarea>
                        </div>

                        <div class="form-group">
                            <label for="">Publish At</label>
                            <input type="date" name="published_at" class="form-control">
                        </div>
                        
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </form>
                    
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

3) Edit Page

Create edit.blade.php file at resources/views/posts folder and paste below code:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Edit Post') }}</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif
                    
                    <form action="/posts/{{$post->id}}" method="post">
                        @csrf
                        @method('PUT')
                        <div class="form-group">
                            <label for="">Post Title</label>
                            <input type="text" name="title" class="form-control" value="{{$post->title}}">
                        </div>

                        <div class="form-group">
                            <label for="">Post Body</label>
                            <textarea name="body" id="" cols="30" rows="10" class="form-control">{{$post->body}}</textarea>
                        </div>

                        <div class="form-group">
                            <label for="">Publish At</label>
                            <input type="date" name="published_at" class="form-control" value="{{ date('Y-m-d', strtotime($post->published_at)) }}">
                        </div>
                        
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </form>
                    
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

4) Show Page (View Post Page)

Create show.blade.php file at resources/views/posts folder and paste below code:

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('View Post') }}</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    <h2>{{$post->title}}</h2>

                    <p>Published At: {{date('Y-m-d', strtotime($post->published_at))}}</p>
                    <br>
                    <div>
                        {{$post->body}}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Step 6): Run Development Serve

It's time to test our app, isn't it?

php artisan serve

We are done! Good Job!

So, this is simple Laravel CRUD Application. Hope I have provided clear explanation to you and it is helpful. If you have any doubts, feel free to comment below or ask in email. I will be glad to help you out.

Adios!