CRUD in Laravel 8

When you install Laravel it has basic scaffolding. It has beautiful updated the Landing Page of Laravel 8.

Lading Page Laravel 8

What is CRUD?

  • Create
  • Read
  • Update
  • Delete

CRUD is a term which refer to Create, Read, Update and Delete. These four operation are fundamental for building any backend. Now a days almost every backend is using database.

When you are using database you will do these operation. So, if you know these operation then you can probably you can make most of application of now a days.

Getting Started

I hope you have installed Laravel and you are ready to get started with writing code. I will not talk about installation because there is good documentation about installing on Laravel website.

https://laravel.com/docs/8.x#installation

Once you install the project then we will create a new project

Terminal
composer create-project --prefer-dist laravel/laravel crud

Creating files using Command

Laravel is one of the best framework and it has outstanding CLI. you can create model, migration and controller using CLI. This make life a lot easier.

Creating Model

To Create model you can use the command

Terminal
$ php artisan make:model products
Model created successfully.
$ 

Creating Migration

Terminal
$ php artisan make:migration products
Created Migration: 2020_11_07_075702_create_products_table
$ 

Creating Controller

Terminal
$ php artisan make:controller products
Controller created successfully.
$

Creating Model Migration and Controller

Terminal
$ php artisan make:model products -mc 
Model created successfully.
Created Migration: 2020_11_07_075702_create_products_table
Controller created successfully.
$ 

Controller

If you have used laravel earlier then there is no major change you will find in the controller. There is one small change which I will talk at then end of this section.

There is four operation CRUD and for that we need at least 7 methods in our controller.

  • Reading all the data - index
  • Reading only one data - read
  • Form for Creating data - create
  • Storing data of data - store
  • Form for Editing data - edit
  • Storing update of data - update
  • Delete Data - delete
app/Http/Controllers/ProductController.php
<?php

namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index(){
        return "Read";
    }
    public function read(){
        return "Read";
    }
    public function create(){
        return "Create";
    }
    public function store(){
        return "Store";
    }
    public function edit(){
        return "Edit";
    }
    public function update(){
        return "Update";
    }
    public function delete(){
        return "Delete";
    }
}

Routes

This has some major change, I am calling this as major change because this change requires us to refactor all the code.

web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController; // Added this line
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

Route::get('/', [ProductController::class, 'index'])->name('product.home');

Route::get('/create', [ProductController::class, 'create'])->name('product.create');
Route::post('/create', [ProductController::class, 'store'])->name('product.store');

Route::get('/{id}/edit', [ProductController::class, 'edit'])->name('product.edit');
Route::put('/{id}/edit', [ProductController::class, 'update'])->name('product.update');

Route::delete('/{id}', [ProductController::class, 'delete'])->name('product.delete');
Route::get('/{id}', [ProductController::class, 'read'])->name('product.read');

Database Schema

Before getting into the frontend let’s build our database and table.

Column Detail Data Type
Name Product Name String
Brand Product Brand String
Price Product Price Number
ID Create a id automatically Number
TimeStamp Maintain the Created and Last modified timestamp DateTime
database/migrations/2020_11_07_081709_create_products_table.php
<?php

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

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->integer('price');
            $table->string('brand');
            $table->timestamps();
        });
    }

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

Building UI

We will use blade, a laravel templating engine. This will gives us power to build UI super quick using various programming php syntax in UI. We can also inherit the file for templating. We don’t need to add the header and footer in different file and include at top and footer like old school days.

First of all, We will create a template file which will look similar to this one.

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">
    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>CRUD APP</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" />
</head>
<body>
    <div id="app">
        <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
            <div class="container">
                <a class="navbar-brand" href="{{ url('/') }}">
                    CRUD APP
                </a>
            </div>
        </nav>

        <main class="py-4">
            @yield('content')
        </main>

    </div>
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>

resources/views/product/add.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8">
            @if (session('status'))
            <div class="alert alert-success">
                {{ session('status') }}
            </div>
            @endif
            <div class="card">
                <div class="card-header">Add Product Form</div>
                <div class="card-body">
                    <form action="{{ route('product.store')}}" method="POST">
                        @csrf
                        <div class="form-group">
                            <label for="name">Name</label>
                            <input type="text" 
                            class="form-control {{  $errors->has('name') ? 'is-invalid' :'' }}" 
                            name="name" id="name" value="{{ old('name')}}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('name') }}
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="price">Price</label>
                            <input type="number" 
                                class="form-control {{  $errors->has('price') ? 'is-invalid' :'' }}" 
                                name="price" id="price" value="{{ old('price')}}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('price') }}
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="brand">Brand</label>
                            <input type="text" 
                                class="form-control {{  $errors->has('brand') ? 'is-invalid' :'' }}" 
                                name="brand" id="brand" value="{{ old('brand')}}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('brand') }}
                            </div>

                        </div>
                        <button type="submit" class="btn btn-primary btn-block">Save</button>
                    </form>
                </div>
            </div>

        </div>
    </div>
</div>

@endsection
resources/views/product/edit.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8">
            @if (session('status'))
            <div class="alert alert-success">
                {{ session('status') }}
            </div>
            @endif
            <div class="card">
                <div class="card-header">Add Product Form</div>
                <div class="card-body">
                    <form action="{{ route('product.update', ['id' => $data->id])}}" method="POST">
                        @csrf
                        <input type="hidden" value="PUT" name="_method">
                        <div class="form-group">
                            <label for="id">ID</label>
                            <input type="text" 
                                class="form-control" 
                                name="id" id="id" value="{{$data->id}}" readonly>
                        </div>
                        <div class="form-group">
                            <label for="name">Name</label>
                            <input type="text" 
                            class="form-control {{  $errors->has('name') ? 'is-invalid' :'' }}" 
                            name="name" id="name" value="{{ old('name') ?? $data->name  }}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('name') }}
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="price">Price</label>
                            <input type="number" 
                                class="form-control {{  $errors->has('price') ? 'is-invalid' :'' }}" 
                                name="price" id="price" value="{{ old('price') ?? $data->price }}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('price') }}
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="brand">Brand</label>
                            <input type="text" 
                                class="form-control {{  $errors->has('brand') ? 'is-invalid' :'' }}" 
                                name="brand" id="brand" value="{{ old('brand') ?? $data->brand}}">
                            <div class="invalid-feedback">
                                {{ $errors->getBag('default')->first('brand') }}
                            </div>
                        </div>

                        <button type="submit" class="btn btn-primary btn-block">Update</button>
                    </form>
                </div>
            </div>

        </div>
    </div>
</div>

@endsection
resources/views/product/home.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    @if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
    @endif

    <div class="d-flex justify-content-end mb-2">
    <a href="{{ route('product.create') }}" class="btn btn-primary">Add Product</a>
    </div>

    <table class="table table-bordered">
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Price</th>
            <th>Action</th>
        </tr>
        @foreach ($data as $product)
        <tr>
            <td>{{ $product->id }}</td>
            <td>{{ $product->name }}</td>
            <td>{{ $product->price }}</td>
            <td>
                <a href="{{ route('product.read',  ['id' => $product->id] )}}" class="btn btn-primary">View</a>
                <a href="{{ route('product.edit', ['id' => $product->id] )}}" class="btn btn-warning">Edit</a>
            </td>
        </tr>
        @endforeach
    </table>
</div>

@endsection
resources/views/product/view.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8">
            <table class="table table-bordered">
                <tr>
                    <th>ID</th>
                    <td>{{ $data->id }}</td>
                </tr>
                <tr>
                    <th>Name</th>
                    <td>{{ $data->name }}</td>
                </tr>
                <tr>
                    <th>Price</th>
                    <td>{{ $data->price }}</td>
                </tr>
                <tr>
                    <th>Brand</th>
                    <td>{{ $data->brand }}</td>
                </tr>
            </table>
            <div class="row">
                <div class="col">
                    <a href="{{ route('product.edit', ['id' => $data->id ]) }}" class="btn btn-primary">Edit</a>
                </div>
                <div class="col">
                    <a href="{{route('product.delete', ['id' => $data->id ])}}" 
                        class="btn btn-danger"
                        onclick="event.preventDefault();document.getElementById('delete-form').submit();"
                        >
                        Delete
                    </a>

                    <form id="delete-form" action="{{ route('product.delete', ['id' => $data->id ]) }}" method="POST" class="d-none">
                        @csrf
                        <input type="hidden" name="_method" value="delete">
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@endsection