Download Laravel App
https://laravel.com/docs/11.x/installation
Connecting our Database
open .env file root directory.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel11dev
DB_USERNAME=root
DB_PASSWORD=root
Create Model and Migration
C:\xampp\htdocs\laravel\laravelproject>php artisan make:model Product -m
A new file named Product.php will be created in the app directory and database/migrations directory to generate the table in our database
app/Models/Product.php
//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',
'image',
'price'
];
}
database\migrations\create_products_table.php
//database\migrations\create_products_table.ph
<?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->string('image');
$table->integer('price');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
Database Migration php artisan migrate
C:\xampp\htdocs\laravel\laravel10project>php artisan migrate
Migration table created successfully.
check database table
Create Controller and Request
C:\xampp\htdocs\laravel\laravel10project>php artisan make:controller ProductController
app\Http\Controllers\ProductController.php
//app\Http\Controllers\ProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product;
use App\Http\Requests\ProductStoreRequest;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage; //php artisan storage:link = php artisan storage:link = http://127.0.0.1:8000/storage/1.jpg
class ProductController extends Controller
{
public function index()
{
//$products = Product::all(); // All Product
$products = Product::paginate(5);
// Return Json Response
return response()->json([
'products' => $products
], 200);
}
public function store(ProductStoreRequest $request)
{
try {
$name = $request->name;
$price = $request->price;
$imageName = Str::random(32) . "." . $request->image->getClientOriginalExtension();
Storage::disk('public')->put($imageName, file_get_contents($request->image));
Product::create([
'name' => $name,
'image' => $imageName,
'price' => $price
]);
// Return Json Response
return response()->json([
'results' => "Product successfully created. '$name' -- '$imageName' -- '$price' "
], 200);
} catch (\Exception $e) {
// Return Json Response
return response()->json([
'message' => "Something went really wrong!"
], 500);
}
}
public function show($id)
{
// Product Detail
$product = Product::find($id);
if (!$product) {
return response()->json([
'message' => 'Product Not Found.'
], 404);
}
// Return Json Response
return response()->json([
'product' => $product
], 200);
}
public function update(ProductStoreRequest $request, $id)
{
try {
// Find product
$product = Product::find($id);
if (!$product) {
return response()->json([
'message' => 'Product Not Found.'
], 404);
}
echo "request : $request->image";
$product->name = $request->name;
$product->price = $request->price;
if ($request->image) {
// Public storage
$storage = Storage::disk('public');
// Old iamge delete
if ($storage->exists($product->image))
$storage->delete($product->image);
// Image name
$imageName = Str::random(32) . "." . $request->image->getClientOriginalExtension();
$product->image = $imageName;
// Image save in public folder
$storage->put($imageName, file_get_contents($request->image));
}
// Update Product
$product->save();
// Return Json Response
return response()->json([
'message' => "Product successfully updated."
], 200);
} catch (\Exception $e) {
// Return Json Response
return response()->json([
'message' => "Something went really wrong!"
], 500);
}
}
public function destroy($id)
{
// Detail
$product = Product::find($id);
if (!$product) {
return response()->json([
'message' => 'Product Not Found.'
], 404);
}
// Public storage
$storage = Storage::disk('public');
// Iamge delete
if ($storage->exists($product->image))
$storage->delete($product->image);
// Delete Product
$product->delete();
// Return Json Response
return response()->json([
'message' => "Product successfully deleted."
], 200);
}
}
php artisan make:request ProductStoreRequest C:\xampp\htdocs\laravel\myapp>php artisan make:request ProductStoreRequest
app\Http\Requests\ProductStoreRequest.php
//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 false;
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
if (request()->isMethod('post')) {
return [
'name' => 'required|string|max:258',
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
'price' => 'required|string'
];
} else {
return [
'name' => 'required|string|max:258',
'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
'price' => 'required|string'
];
}
}
public function messages()
{
if (request()->isMethod('post')) {
return [
'name.required' => 'Name is required!',
'image.required' => 'Image is required!',
'price.required' => 'Price'
];
} else {
return [
'name.required' => 'Name is required!',
'price.required' => 'Price is required!'
];
}
}
}
routes/api.php
//routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
Route::get('products', [ProductController::class, 'index']);
Route::post('products', [ProductController::class, 'store']);
Route::get('products/{id}', [ProductController::class, 'show']);
Route::put('productsupdate/{id}', [ProductController::class, 'update']);
Route::delete('productdelete/{id}', [ProductController::class, 'destroy']);
Run C:\xampp\htdocs\laravel\myapp>php artisan serve Starting Laravel development server: http://127.0.0.1:8000/api/products
generate symbolic links C:\xampp\htdocs\laravel\myapp>php artisan storage:link
Run C:\xampp\htdocs\laravel\myapp>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
open postman new request
GET api/products Index All products return.
GET : http://127.0.0.1:8000/api/products
GET api/products/{id} Show Detail of a particular post by ID.
GET : http://127.0.0.1:8000/api/products/1
POST api/products Store Create a new product.
POST : http://127.0.0.1:8000/api/products
body
key value
name Iphone 13
image iphone.jpg = file
price 45
PUT api/products/{id} Update Update a particular product by ID.
POST : http://127.0.0.1:8000/api/products/1
body
key value
_method PUT
name Iphone 13 updated
image iphone.jpg = file
price 46 updated
DELETE api/products/{id} Destroy Delete a particular product by ID.
DELETE : http://127.0.0.1:8000/api/products/1
Install nextjs
https://nextjs.org/
npx create-next-app@latest
install axios
npm install axios
https://www.npmjs.com/package/axios
app\page.tsx
app\page.tsx
//app\page.tsx
import Link from "next/link";
import ProductsTable from "@/components/tabledata";
import { Suspense } from "react";
import { Spinner } from "@/components/spinner";
export default function Home() {
return (
<div className="w-screen py-20 flex justify-center flex-col items-center">
<div className="flex items-center justify-between gap-1 mb-5">
<h1 className="text-4xl font-bold">Next.js 14 Laravel 11 CRUD with Upload and Pagination <br/>(Create, Read, Update and Delete) Mysql | TailwindCSS DaisyUI</h1>
</div>
<div className="overflow-x-auto">
<div className="mb-2 w-full text-right">
<Link
href="/product/create"
className="btn btn-primary">
Add New Product
</Link>
</div>
<Suspense fallback={<Spinner />}>
<ProductsTable/>
</Suspense>
</div>
</div>
);
}
components\tabledata.tsx
//components\tabledata.tsx
"use client";
import React, { useEffect, useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import Image from 'next/image'
export default function Products() {
const [productsData, setProductsData] = useState([]);
const [pageprevnext, setPage] = useState({});
const url = "http://127.0.0.1:8000/api/products";
useEffect(() => {
fetchData(url);
}, []);
const fetchData = (url) => {
axios
.get(url)
.then((data) => {
setProductsData(data.data.products.data);
console.log(data.data.products.data);
setPage(data.data.products);
//console.log(data.data.products.next_page_url);
})
.catch((error) => {
console.log(error);
});
};
const handleNextPage = () => {
console.log(pageprevnext.next_page_url);
fetchData(pageprevnext.next_page_url);
window.scrollTo(0, 0);
};
const handlePreviousPage = () => {
fetchData(pageprevnext.prev_page_url);
window.scrollTo(0, 0);
};
const deleteProduct = (id) => {
axios.delete('http://127.0.0.1:8000/api/productdelete/'+id).then(function(response){
console.log(response.data);
alert("Successfully Deleted");
window.location.href = '/';
});
}
return (
<>
<table className="table table-zebra">
<thead className="text-sm text-gray-700 uppercase bg-gray-50">
<tr>
<th className="py-3 px-6">#</th>
<th className="py-3 px-6">Photo</th>
<th className="py-3 px-6">Name</th>
<th className="py-3 px-6">Price</th>
<th className="py-3 px-6 text-center">Actions</th>
</tr>
</thead>
<tbody>
{productsData.map((rs, index) => (
<tr key={rs.id} className="bg-white border-b">
<td className="py-3 px-6">{rs.id}</td>
<td className="py-3 px-6">
<Image
src={`http://127.0.0.1:8000/storage/${rs.image}`}
width={70}
height={70}
style={{width:'90px', height: "auto" }}
alt="Photo"
/>
</td>
<td className="py-3 px-6">{rs.name}</td>
<td className="py-3 px-6">${rs.price}.99</td>
<td className="flex justify-center gap-1 py-3">
<Link
href={`/product/view/${rs.id}`}
className="btn btn-info">
View
</Link>
<Link
href={`/product/edit/${rs.id}`}
className="btn btn-primary">
Edit
</Link>
<button onClick={() => deleteProduct(rs.id)} className="btn btn-secondary">Delete</button>
</td>
</tr>
))}
</tbody>
</table>
<div className="w-1/2 items-center px-4 mt-6">
<div className="join grid grid-cols-2">
{pageprevnext.prev_page_url ? (
<button className="join-item btn btn-primary btn-outline" onClick={handlePreviousPage}>
Previous
</button>
) : null}
{pageprevnext.next_page_url ? (
<button className="join-item btn btn-primary btn-outline" onClick={handleNextPage}>
Next
</button>
) : null}
</div>
</div>
</>
);
}
components\spinner.tsx
//components\spinner.tsx
export const Spinner = () => {
return (
<span className="loading loading-spinner loading-lg"></span>
);
};
app\product\create\page.tsx
//app\product\create\page.tsx
"use client";
import React, { useState } from "react";
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
const Product = () => {
const [name, setName] = useState("");
const [price, setPrice] = useState("");
const [image, setFile] = useState()
const onSubmitUpload = async (e) => {
e.preventDefault();
try {
const formData = new FormData()
formData.append("name", name);
formData.append("price", price);
formData.append('image', image)
axios.post('http://127.0.0.1:8000/api/products',formData )
.then((response) => {
console.log(response);
window.location.href = '/';
})
.catch(er => console.log(er))
} catch (err) {
console.log("Something Wrong");
}
}
return (
<div className="max-w-md mx-auto mt-5">
<h1 className="text-2xl text-center mb-2">Add New Product</h1>
<div>
<form>
<div className="mb-5">
<label htmlFor="name" className="block text-sm font-medium text-gray-900">
Name
</label>
<input
type="text"
name="name"
id="name"
className="input input-bordered input-primary w-full max-w-xs"
placeholder="Name..."
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className="mb-5">
<label htmlFor="price" className="block text-sm font-medium text-gray-900">
Price
</label>
<input
type="price"
name="price"
id="price"
className="input input-bordered input-primary w-full max-w-xs"
placeholder="price..."
onChange={(e) => setPrice(e.target.value)}
/>
</div>
<div className="mb-5">
<label className="block text-sm font-medium text-gray-900">
Upload File
</label>
<input type="file" onChange={(e) => setFile(e.target.files[0])} name="image" id="image" className="file-input file-input-bordered file-input-secondary w-full max-w-xs"/>
</div>
<button type="submit" className="btn btn-primary" onClick={e => onSubmitUpload(e)}>Add New Product</button>
</form>
</div>
</div>
);
};
export default Product;
app\product\edit\[id]\page.tsx
//app\product\edit\[id]\page.tsx
"use client";
import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import { useParams } from 'next/navigation'
import Image from 'next/image'
export default function ViewProductPage() {
const {id}=useParams();
console.log(id);
useEffect(()=>{
fetchProduct();
},[id]);
const fetchProduct=async()=>{
try{
const result=await axios.get("http://127.0.0.1:8000/api/products/"+id);
console.log(result.data.product);
setInputs(result.data.product)
}catch(err){
console.log("Something Wrong");
}
}
const[message, setMessage]= useState('');
const [inputs, setInputs] = useState([]);
const [fileimage, setPhoto]= useState('');
const handleChange = (event) => {
const name = event.target.name;
const value = event.target.value;
setInputs(values => ({...values, [name]: value}));
}
const uploadProduct= async()=>{
const formData= new FormData();
formData.append('_method', 'PUT');
formData.append('name', inputs.name);
formData.append('price',inputs.price);
formData.append('image', fileimage);
const response= await axios.post("http://127.0.0.1:8000/api/productsupdate/"+id, formData, {
headers:{'Content-Type':"multipart/form-data"},
} );
setMessage(response.data.message); //"message": "Product successfully updated.."
console.log(response)
setTimeout(()=>{
window.location.href = '/';
}, 2000);
}
const handleSubmit= async(e)=>{
e.preventDefault();
await uploadProduct();
}
return (
<div className="max-w-md mx-auto mt-5">
<h1 className="text-2xl text-center mb-2">Edit Form</h1>
<p className="text-success"><b>{ message }</b></p>
<form onSubmit={ handleSubmit}>
<div className="mb-3 mt-3">
<label className="block text-sm font-medium text-gray-900"> ID:</label>
<input type="text" id="id" name="id" value={id} disabled />
</div>
<div className="mb-3 mt-3">
<label className="block text-sm font-medium text-gray-900"> Full Name:</label>
<input type="text" className="input input-bordered input-primary w-full max-w-xs" placeholder="Enter Your Full Name" name="name"
value={inputs.name} onChange={ handleChange}/>
</div>
<div className="mb-3 mt-3">
<label className="block text-sm font-medium text-gray-900">Price:</label>
<input type="text" className="input input-bordered input-primary w-full max-w-xs" id="price" placeholder="Enter Price" name="price"
value={inputs.price} onChange={ handleChange}/>
</div>
<div className="mb-5">
<label className="block text-sm font-medium text-gray-900">
Upload File
</label>
<input type="file" onChange={(e)=>setPhoto(e.target.files[0])} name="image" id="image" className="file-input file-input-bordered file-input-secondary w-full max-w-xs"/>
</div>
<p className="text-center mt-6">
<Image
src={`http://127.0.0.1:8000/storage/${inputs.image}`}
width={200}
height={200}
alt="Photo"
style={{width:'400px', height: "auto" }}
/>
</p>
<button type="submit" className="btn btn-primary">Update</button>
</form>
</div>
);
}
app\product\view\[id]\page.tsx
//app\product\view\[id]\page.tsx
"use client";
import React, { useState, useEffect } from 'react';
import axios from 'axios' //npm install axios https://www.npmjs.com/package/axios
import Link from "next/link";
import { useParams } from 'next/navigation'
import Image from 'next/image'
export default function ViewProductPage() {
const {id}=useParams();
console.log(id);
const[product,setProduct]=useState([]);
useEffect(()=>{
fetchProduct();
},[id]);
const fetchProduct=async()=>{
try{
const result=await axios.get("http://127.0.0.1:8000/api/products/"+id);
console.log(result.data.product);
setProduct(result.data.product)
}catch(err){
console.log("Something Wrong");
}
}
return (
<div className="max-w-2xl mx-auto mt-5">
<h1 className="text-2xl text-center mb-2">View Product</h1>
<table className="table table-zebra">
<thead className="text-sm text-gray-700 uppercase bg-gray-50">
<tr>
<th>S No.</th>
<th>Product Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>{product.id}</td>
<td>{product.name}</td>
<td>{product.price}</td>
</tr>
</tbody>
</table>
<p className="text-center mt-6">
<Image
src={`http://127.0.0.1:8000/storage/${product.image}`}
width={200}
height={200}
alt="Photo"
style={{width:'400px', height: "auto" }}
/>
</p>
</div>
);
}
next.config.mjs
/** @type {import('next').NextConfig} */
//const nextConfig = {};
const nextConfig = {
reactStrictMode: true,
images : {
domains : ['localhost', 'cairocoders-ednalan.com', '127.0.0.1'] // == Domain name
}
}
export default nextConfig;
run C:\nextjs>npm run dev Github - Next.js 14 Laravel 11 CRUD with Upload and Pagination (Create, Read, Update and Delete) Mysql | TailwindCSS DaisyUI
