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