• May 3, 2024
  • Chiwetara Igwe
  • 0

In this tutorial, you are going to learn step by step on how to create a crud operation with Laravel.

CRUD refers to the four basic operations a software application should be able to perform – Create, Read, Update, and Delete.

We will create a product CRUD application using Laravel. In this example, We will create a products table with name, price, and description columns using Laravel migration. Then, we will create routes, a controller, views, and model files for the product application. We will use Bootstrap 5 for design. So, let’s follow the steps below to create CRUD operations with Laravel.

Step 1: Install Laravel 11

First of all, we need to ensure that we have installed a laravel project. if it is not yet installed, we will use the command below to install a new project from scratch. So, open your terminal or command prompt and run the command below:

composer create-project laravel/laravel laravel-project

Step 2: MySQL Database Configuration

After installation, when you open .env file, you will discover that by default that the database connection is set to sqlite in Laravel 11. in this tutorial, you need to switch to use mysql as shown below. the next thing to do is setup your database configuaration.

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=enter your database name(laravel-projects)
DB_USERNAME=enter database username(root)
DB_PASSWORD=enter database password(root)

Step 3: Create Migration

In the third step, we will create a “products” table with “name“, “price” and “description” columns using Laravel migration. So, let’s use the following command to create a migration file:

php artisan make:migration create_products_table --create=products

After executing the above command, you will find a file in the following path: “database/migrations”. You have to put the code below in your migration file to create the products table.

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->decimal('price', 20, 2);
            $table->timestamps();
        });
    }

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

Now you have to run this migration by the following command:

php artisan migrate

Step 4: Create Form Request Validation Class

In this step, we will create a form request validation class for the `store()` and `update()` methods in the controller. In this class, we will define validation rules and use it in the controller file. So, let’s create it.

php artisan make:request ProductStoreRequest

Just put the below code in your request class:

app/Http/Requests/ProductStoreRequest.php

<?php
  
namespace App\Http\Requests;
  
use Illuminate\Foundation\Http\FormRequest;
  
class ProductStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }
  
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array|string>
     */
    public function rules(): array
    {
        return [
            "name" => 'required',
            "price" => 'required',
            "description" => 'required',
        ];
    }
}

Now, let’s do the same thing for the Update Request Class.

php artisan make:request ProductUpdateRequest

Just put the below code in your request class:

app/Http/Requests/ProductUpdateRequest.php

<?php
   
namespace App\Http\Requests;
  
use Illuminate\Foundation\Http\FormRequest;
  
class ProductUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array|string>
     */
    public function rules(): array
    {
        return [
            "name" => 'required',
            "price" => 'required',
            "description" => 'required',
        ];
    }
}

Step 5: Create Controller and Model

In this step, now we should create a new resource controller named ProductController. So run the below command to create the new controller. Below is the controller for creating the resource controller.

php artisan make:controller ProductController --resource --model=Product

After the following command, you will find a new file at this path: “app/Http/Controllers/ProductController.php”.

In this controller, seven methods will be created by default as follows:

  1. index()
  2. create()
  3. store()
  4. show()
  5. edit()
  6. inform()
  7. destroy()

So, let’s copy the code below and put it in the ProductController.php file.

app/Http/Controllers/ProductController.php

<?php

namespace App\Http\Controllers;

use App\Http\Requests\ProductStoreRequest;
use App\Http\Requests\ProductUpdateRequest;
use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {

        $products = Product::latest()->paginate(5);

        return view('products.index', ['products' => $products]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        return view('products.create');
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(ProductStoreRequest $request)
    {

        Product::create($request->validated());

        session()->flash('success', 'Product created successfully.');

        return redirect()->route('products.index');

    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $product = Product::find($id);

        return view('products.show', compact('product'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(string $id)
    {

        $product = Product::find($id);


        return view('products.edit', compact('product'));

    }

    /**
     * Update the specified resource in storage.
     */
    public function update(ProductUpdateRequest $request, string $id)
    {

        $product = Product::find($id);

        $product->update($request->validated());

        session()->flash('success', 'Product updated successfully.');

        return redirect()->route('products.index');

    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(string $id)
    {
        Product::find($id)->delete();

        session()->flash('success','Product deleted successfully');

        return redirect()->route('products.index');
    }
}

So, let’s update the Product model code as follows:Ezoic

app/Models/Product.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class Product extends Model
{
    use HasFactory;
  
    protected $fillable = [
        "name",
        "price",
        "description",
    ];
}

Step 6: Add Resource Route

Here, we need to add a resource route for the product CRUD application. So, open your `routes/web.php` file and add the following route.

routes/web.php

<?php
  
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
  
Route::resource('products', ProductController::class);

Step 7: Update AppServiceProvider

Here, we will use bootstrap 5 for pagination. so, we need to import it on AppServiceProvider.php file. let’s update it.

app/Provides/AppServiceProvider.php

<?php
  
namespace App\Providers;
  
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
  
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
           
    }
  
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Paginator::useBootstrapFive();
    }
}

Step 8: Add Blade Files

In the last step, we need to two folders and blade files. the first folder will named layout. it will contain our master file and another folder named products. After that, we will create blade files inside our products folder. So, finally, you have to create the following blade files below:

  1. layouts/master.blade.php
  2. products/index.blade.php
  3. products/create.blade.php
  4. products/edit.blade.php
  5. products/show.blade.php

So let’s just create the following file and put the code below in it.

resources/views/products/layout.blade.php

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Products</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</head>

<body>

    <div class="container">
        <header class="d-flex flex-wrap justify-content-center py-3 mb-4 border-bottom">

            <a href="/"
                class="d-flex align-items-center mb-3 mb-md-0 me-md-auto link-body-emphasis text-decoration-none">
                <svg class="bi me-2" width="40" height="32">
                    <use xlink:href="#bootstrap" />
                </svg>
                <span class="fs-4">Simple header</span>
            </a>

            <ul class="nav nav-pills">
                <li class="nav-item"><a href="#" class="nav-link active" aria-current="page">Home</a></li>
                <li class="nav-item"><a href="#" class="nav-link">Features</a></li>
                <li class="nav-item"><a href="#" class="nav-link">Pricing</a></li>
                <li class="nav-item"><a href="#" class="nav-link">FAQs</a></li>
                <li class="nav-item"><a href="#" class="nav-link">About</a></li>
            </ul>

        </header>
    </div>
    <div class="container mt-5 mb-5">
        @yield('content')
    </div>

    <div class="container">
        <footer class="py-5">
            <div class="row">
                <div class="col-6 col-md-2 mb-3">
                    <h5>Section</h5>
                    <ul class="nav flex-column">
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Home</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#"
                                class="nav-link p-0 text-body-secondary">Features</a></li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Pricing</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">FAQs</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">About</a>
                        </li>
                    </ul>
                </div>

                <div class="col-6 col-md-2 mb-3">
                    <h5>Section</h5>
                    <ul class="nav flex-column">
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Home</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#"
                                class="nav-link p-0 text-body-secondary">Features</a></li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Pricing</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">FAQs</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">About</a>
                        </li>
                    </ul>
                </div>

                <div class="col-6 col-md-2 mb-3">
                    <h5>Section</h5>
                    <ul class="nav flex-column">
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Home</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#"
                                class="nav-link p-0 text-body-secondary">Features</a></li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">Pricing</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">FAQs</a>
                        </li>
                        <li class="nav-item mb-2"><a href="#" class="nav-link p-0 text-body-secondary">About</a>
                        </li>
                    </ul>
                </div>

                <div class="col-md-5 offset-md-1 mb-3">
                    <form>
                        <h5>Subscribe to our newsletter</h5>
                        <p>Monthly digest of what's new and exciting from us.</p>
                        <div class="d-flex flex-column flex-sm-row w-100 gap-2">
                            <label for="newsletter1" class="visually-hidden">Email address</label>
                            <input id="newsletter1" type="text" class="form-control" placeholder="Email address"
                                spellcheck="false" data-ms-editor="true">
                            <button class="btn btn-primary" type="button">Subscribe</button>
                        </div>
                    </form>
                </div>
            </div>

            <div class="d-flex flex-column flex-sm-row justify-content-between py-4 my-4 border-top">
                <p>© 2024 Company, Inc. All rights reserved.</p>
                <ul class="list-unstyled d-flex">
                    <li class="ms-3"><a class="link-body-emphasis" href="#"><svg class="bi"
                                width="24" height="24">
                                <use xlink:href="#twitter"></use>
                            </svg></a></li>
                    <li class="ms-3"><a class="link-body-emphasis" href="#"><svg class="bi"
                                width="24" height="24">
                                <use xlink:href="#instagram"></use>
                            </svg></a></li>
                    <li class="ms-3"><a class="link-body-emphasis" href="#"><svg class="bi"
                                width="24" height="24">
                                <use xlink:href="#facebook"></use>
                            </svg></a></li>
                </ul>
            </div>
        </footer>
    </div>

</body>

</html>

resources/views/products/index.blade.php

@extends('layouts.master')

@section('content')
    <div class="card">
        <div class="card-header">
            <div class="d-grid gap-2 d-flex justify-content-between align-items-center">
                <h5>List of products</h5>
                <a href="{{ route('products.create') }}" class="btn btn-primary">Create Product</a>
            </div>
        </div>
        <div class="card-body">

            @session('success')
                <div class="alert alert-success" role="alert"> {{ $value }} </div>
            @endsession

            <table class="table table-striped">
                <thead>
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">name</th>
                        <th scope="col">price</th>
                        <th scope="col">Action</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach ($products as $product)
                        <tr>
                            <th scope="row">{{ $product->id }}</th>
                            <td>{{ $product->name }}</td>
                            <td>{{ $product->price }}</td>
                            <td>
                                <div class="dropdown">
                                    <a class="btn btn-defualt dropdown-toggle" href="#" role="button"
                                        data-bs-toggle="dropdown" aria-expanded="false">
                                    </a>

                                    <ul class="dropdown-menu">
                                        <li><a class="dropdown-item"
                                                href="{{ route('products.show', $product->id) }}">View</a></li>
                                        <li>
                                        <li><a class="dropdown-item"
                                                href="{{ route('products.edit', $product->id) }}">Edit</a></li>
                                        <li>
                                            <form action="{{ route('products.destroy', $product->id) }}" method="post">
                                                @method('DELETE')
                                                @csrf
                                                <button class="dropdown-item" type="submit"
                                                    href="{{ route('products.destroy', $product->id) }}">Delete</button>
                                            </form>
                                        </li>
                                    </ul>
                                </div>
                            </td>
                        </tr>
                    @endforeach


                </tbody>

            </table>
        </div>
        <div class="card-footer">
            {!! $products->links() !!}
        </div>
    </div>
@endsection

resources/views/products/create.blade.php

@extends('layouts.master')

@section('content')
    <form action="{{ route('products.store') }}" method="post" enctype="multipart/form-data">
        @csrf
        <div class="card">
            <div class="card-header d-grid gap-2 d-flex justify-content-between align-items-center">
                <h5>Create Product</h5>
                <a href="{{ route('products.index') }}" class="btn btn-primary">List of Products</a>
            </div>
            <div class="card-body">
                <div class="mb-3">
                    <label for="formFile" class="form-label">Name</label>
                    <input class="form-control @error('name') is-invalid @enderror" value="{{ old('name') }}"
                        name="name">
                    @error('name')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="formFile" class="form-label">Price</label>
                    <input class="form-control @error('price') is-invalid @enderror" type="number"
                        value="{{ old('price') }}" name="price">
                    @error('price')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="formFile" class="form-label">Descriptions</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" name="description">{{ old('description') }}</textarea>
                    @error('description')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>
            </div>
            <div class="card-footer">
                <div class="col-12">
                    <button class="btn btn-primary float-end" type="submit">Submit form</button>
                </div>
            </div>
        </div>
    </form>
@endsection

resources/views/products/edit.blade.php

@extends('layouts.master')

@section('content')
    <form action="{{ route('products.update', $product->id) }}" method="post" enctype="multipart/form-data">
        @csrf
        @method('PATCH')
        <div class="card">
            <div class="card-header">
                <div class="d-grid gap-2 d-flex justify-content-between">
                    <h5>Edit Product</h5>
                    <a href="{{ route('products.create') }}" class="btn btn-primary">Create Product</a>
                </div>
            </div>
            <div class="card-body">


                <div class="mb-3">
                    <label for="formFile" class="form-label">Name</label>
                    <input class="form-control @error('name') is-invalid @enderror" value="{{ old('name', $product->name) }}" name="name">
                    @error('name')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="formFile" class="form-label">Price</label>
                    <input class="form-control @error('price') is-invalid @enderror" type="number" value="{{ old('price', $product->price) }}" name="price">
                    @error('price')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="formFile" class="form-label">Descriptions</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" name="description">{{ old('description', $product->description) }}</textarea>
                    @error('description')
                        <div class="form-text text-danger">{{ $message }}</div>
                    @enderror
                </div>

            </div>
            <div class="card-footer">
                <div class="col-12">
                    <button class="btn btn-primary float-end" type="submit">Submit form</button>
                </div>
            </div>
        </div>
    </form>
@endsection

resources/views/products/show.blade.php

@extends('layouts.master')

@section('content')
    <div class="card">
        <div class="card-header">
            <div class="d-grid gap-2 d-flex justify-content-between align-items-center">
                <h5>View Product</h5>
                <a href="{{ route('products.create') }}" class="btn btn-primary">Create Product</a>
            </div>
        </div>
        <div class="card-body">
            <p>Product Name: {{ $product->name }}</p>
            <p>Product Price: {{ $product->price }}</p>
            <p>Product Description: {{ $product->description }}</p>
        </div>
    </div>
@endsection

Run Laravel App:Ezoic

All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:

php artisan serve

Now, Go to your web browser, type the given URL and view the app output:

http://localhost:8000/products

You will see layout bellow:

Chiwetara Igwe

I'm a full-stack developer, entrepreneur and owner of techbly.ng. I live in Nigeria and I love to write tutorials and tips that can help to other web developers. I am experienced in PHP, Laravel, Angular, Vue, Node, Javascript, JQuery, Codeigniter and Bootstrap. I am passionate about learning new things and keeping up with the latest trends and technologies.

http://techbly.ng

Leave a Reply

Your email address will not be published. Required fields are marked *

× Have a question?