Blog Details
Md. Kawsar Ahmad
20 Oct 2024
8 min read
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!
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!
I assume you have a local server and Composer installed on your device. Let's start with project initialization.
composer create-project laravel/laravel my-app
cd my-app
.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=
Route::resource('products', ProductController::class);
php artisan make:controller ProductController --resource
php artisan make:model Product -m
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();
});
}
protected $fillable = [
'name',
'description',
'price',
'image',
];
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'));
}
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'));
}
public function create()
{
return view('products.create');
}
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.');
}
public function show(Product $product)
{
return view('products.show', compact('product'));
}
public function edit(Product $product)
{
return view('products.edit', compact('product'));
}
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.');
}
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.');
}
<!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>
@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
@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
@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
@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
php artisan migrate:fresh --seed
php artisan serve
if you see this in your cmd that means your app is served locally and ready to explore:
http://127.0.0.1:8000/products
Don’t worry, we don’t spam!