How To Create Laravel 11 CRUD App with Image Upload in 5 Minutes

How To Create Laravel 11 CRUD App with Image Upload in 5 Minutes image

Last Update: 20 Oct 2024

Introduction

Laravel is known for its regular updates and improvements with each new release. This can be scary for some beginners. It goes like, "Oh no! Just got a hold of Laravel 9.x or 10.x, and then boom! There comes Laravel 11!! How will I cope with this?" Don't be afraid of those fears since they are basically baseless. The core concepts and syntax remain familiar, and all changes here are to help make your development experience smoother.

Actually, Laravel 11 comes with an even more streamlined, lightweight boilerplate.
By default, it includes only what is absolutely necessary; therefore, resources are at a minimum consumption level. Of course, if you need more, all that is easily installable via Composer.

In this article, we will learn about Laravel 11 CRUD with image upload. I'm going to teach you step by step, using a clean and basic structure. You will see after this guide how quickly and effectively CRUD can be developed in only 5 minutes.

So let's get started!

content image

Project Structure

here we basically used default bootstrap html layout to get a basic view in our app you can decorate your app as you want.

here we have focused only on the functional process so don't think of templating just make it in your own way!

Project Initialization and Configuration

I assume you have a local server and Composer installed on your device. Let's start with project initialization.

 

  • open your cmd and navigate in your local server's www folder and type this below code:
composer create-project laravel/laravel my-app
  • After running this command, Composer will give you a fully configured Laravel app. After the installation, go to the my-app folder
cd my-app
  • Congratulations! now you're inside your created app, now navigate the .env  file and rename your app name and configure database configuration like this example:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=
  • Congratulations! your project initialization and configuration is complete

Let's create Route, Model, Migration, Controller

  • First, let's create a Resource route for Product. This will generate all the needed routes in the background. This way, we keep the codebase simple while showing just one route declaration.
Route::resource('products', ProductController::class);
  • To create the Controller, In your cmd write this:
php artisan make:controller ProductController --resource
  • Now lets create a model and migration in just one command by writing this on cmd:
php artisan make:model Product -m
  • Let's complete the migration by defining the schema. Open the generated migration file in your database/migrations. Then, write this demo code:
    public function up(): void
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description');
            $table->decimal('price', 8, 2);
            $table->string('image')->nullable();
            $table->timestamps();
        });
    }
  • Assign fillable properties in your Model to define which fields are going to be filled by the users. open app/Models navigate the Product model and write this:
protected $fillable = [
        'name',
        'description',
        'price',
        'image',
    ];
  • Now Let's finish our Controller code, at first navigate app/Http/Controllers/Productcontroller and write index method:
    public function index()
    {
        //fetching all the products from the database via model
        $products = Product::all();
        //pass all the data in the view
        return view('products.index', compact('products'));
    }

 

Let's make it functional with Controller

  • Now Let's finish our Controller code, at first navigate app/Http/Controllers/Productcontroller and write index() method:
    public function index()
    {
        //fetching all the products from the database via model
        $products = Product::all();
        //pass all the data in the view
        return view('products.index', compact('products'));
    }
  • Now we will write our create() method code:
    public function create()
    {
        return view('products.create');
    }
  • Now we can make our store() method functional write this:
  public function store(Request $request)
    {

      // validate the request data
        $request->validate([
            'name' => 'required',
            'description' => 'required',
            'price' => 'required',
            'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048'
        ]);
      //  assigning filepath of the storage
        $imagePath = null;
        if ($request->hasFile('image')) {
            $imagePath = $request->file('image')->store('images', 'public');
        }

        Product::create([
            'name' => $request->name,
            'description' => $request->description,
            'price' => $request->price,
            'image' => $imagePath,
        ]);
      // redirecting to the index page
        return redirect()->route('products.index')->with('success', 'Product created successfully.');
    }
  • Now we will write our show() method code to show soecific selected product in the controller write this:
    public function show(Product $product)
    {
        return view('products.show', compact('product'));
    }
  • In your Product controller edit() method paste this to redirect your edit form:
    public function edit(Product $product)
    {
        return view('products.edit', compact('product'));
    }
  • find the update() method and paste this code:
 public function update(Request $request, Product $product)
    {
        $request->validate([
            'name' => 'required',
            'description' => 'required',
            'price' => 'required',
            'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:2048'
        ]);

        $imagePath = $product->image;
        if ($request->hasFile('image')) {
            if ($imagePath) {
                // Delete the old image
                Storage::disk('public')->delete($imagePath);
            }
            $imagePath = $request->file('image')->store('images', 'public');
        }

        $product->update([
            'name' => $request->name,
            'description' => $request->description,
            'price' => $request->price,
            'image' => $imagePath,
        ]);

        return redirect()->route('products.index')->with('success', 'Product updated successfully.');
    }
  • It's almost finished with controller just paste this code in your destroy() method to complete the controller:
    public function destroy(Product $product)
    {
        if ($product->image) {
            Storage::disk('public')->delete($product->image);
        }
        $product->delete();
        return redirect()->route('products.index')->with('success', 'Product deleted successfully.');
    }

 

Let's Visualize with View

  • here is our view demo structure of our project:

  • At first let's craete a folder layouts in resources/views and create app.blade.php and paste this demo code:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Laravel CRUD</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container-fluid">
            <a class="navbar-brand" href="{{ route('products.index') }}">Product Manager</a>
        </div>
    </nav>
    <div class="container mt-4">
        @yield('content')
    </div>
</body>
</html>
  • Open your Products/index.blade.php and paste this code:
@extends('layouts.app')

@section('content')
    <div class="container">
        <h2>Products</h2>
        <a href="{{ route('products.create') }}" class="btn btn-primary">Create Product</a>

        @if (session('success'))
            <div class="alert alert-success mt-3">{{ session('success') }}</div>
        @endif

        <table class="table mt-3">
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Description</th>
                    <th>Price</th>
                    <th>Image</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                @foreach($products as $product)
                    <tr>
                        <td>{{ $product->name }}</td>
                        <td>{{ $product->description }}</td>
                        <td>{{ $product->price }}</td>
                        <td>
                            @if($product->image)
                                <img src="{{ asset('storage/' . $product->image) }}" alt="{{ $product->name }}" width="150">
                            @endif
                        </td>
                        <td>
                            <a href="{{ route('products.show', $product->id) }}" class="btn btn-info">Show</a>
                            <a href="{{ route('products.edit', $product->id) }}" class="btn btn-warning">Edit</a>
                            <form action="{{ route('products.destroy', $product->id) }}" method="POST" class="d-inline-block">
                                @csrf
                                @method('DELETE')
                                <button type="submit" class="btn btn-danger">Delete</button>
                            </form>
                        </td>
                    </tr>
                @endforeach
            </tbody>
        </table>
    </div>
@endsection
  • Open your Products/create.blade.php and paste this code:
@extends('layouts.app')

@section('content')
    <div class="container">
        <h2>Create Product</h2>
        <form action="{{ route('products.store') }}" method="POST" enctype="multipart/form-data">
            @csrf
            <div class="form-group">
                <label for="name">Name</label>
                <input type="text" name="name" class="form-control" required>
            </div>

            <div class="form-group">
                <label for="description">Description</label>
                <textarea name="description" class="form-control" required></textarea>
            </div>

            <div class="form-group">
                <label for="price">Price</label>
                <input type="text" name="price" class="form-control" required>
            </div>

            <div class="form-group">
                <label for="image">Image</label>
                <input type="file" name="image" class="form-control">
            </div>

            <button type="submit" class="btn btn-success">Create</button>
        </form>
    </div>
@endsection
  • Now in your Products/edit.blade.php paste this code:
@extends('layouts.app')

@section('content')
    <div class="container">
        <h2>Edit Product</h2>
        <form action="{{ route('products.update', $product->id) }}" method="POST" enctype="multipart/form-data">
            @csrf
            @method('PUT')

            <div class="form-group">
                <label for="name">Name</label>
                <input type="text" name="name" value="{{ $product->name }}" class="form-control" required>
            </div>

            <div class="form-group">
                <label for="description">Description</label>
                <textarea name="description" class="form-control" required>{{ $product->description }}</textarea>
            </div>

            <div class="form-group">
                <label for="price">Price</label>
                <input type="text" name="price" value="{{ $product->price }}" class="form-control" required>
            </div>

            <div class="form-group">
                <label for="image">Image</label>
                @if ($product->image)
                    <img src="{{ asset('storage/' . $product->image) }}" alt="image" width="100">
                @endif
                <input type="file" name="image" class="form-control">
            </div>

            <button type="submit" class="btn btn-success">Update</button>
        </form>
    </div>
@endsection
  • Open your Products/edit.blade.php and paste this code:
@extends('layouts.app')

@section('content')
    <div class="container mt-5">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card shadow-sm">
                    <div class="row g-0">
                        @if ($product->image)
                            <div class="col-md-4">
                                <img src="{{ asset('storage/' . $product->image) }}" alt="{{ $product->name }}" class="img-fluid rounded-start">
                            </div>
                        @endif
                        <div class="{{ $product->image ? 'col-md-8' : 'col-md-12' }}">
                            <div class="card-body">
                                <h3 class="card-title">{{ $product->name }}</h3>
                                <p class="card-text"><strong>Description:</strong> {{ $product->description }}</p>
                                <p class="card-text"><strong>Price:</strong> {{ $product->price }} BDT</p>
                                <div class="mt-4">
                                    <a href="{{ route('products.index') }}" class="btn btn-primary">Back to Products</a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

 

Finish it with migrate and serve

  • You are done with your View configuration next step is just to migrate your database schema  via artisan command:
php artisan migrate:fresh --seed
  • Hence all the datbase schema is successfully migrated now you can serve your app with this command in cmd:
php artisan serve

if you see this in your cmd that means your app is served locally and ready to explore:

  • Now Open your browser and paste this link  in your browser tab to explore your app :
http://127.0.0.1:8000/products

Ready to use the app

Frequently Asked Questions

Get the best of our content straight to your inbox!

Don’t worry, we don’t spam!