DEV Community

Yuki Shiroi
Yuki Shiroi

Posted on

sample laravel set up easy

PART 1: Setup

composer create-project laravel/laravel fruit-system
cd fruit-system
Create database in phpMyAdmin:

fruit_db
Edit .env:

DB_DATABASE=fruit_db
DB_USERNAME=root
DB_PASSWORD=

Install Breeze:

composer require laravel/breeze --dev
php artisan breeze:install blade
php artisan migrate
npm install
npm run build
Install Bootstrap UI and PDF only:

npm uninstall tailwindcss postcss autoprefixer

composer require aldhix/breeze-bootstrap-ui
php artisan breeze-bootstrap-ui:install --force
composer require barryvdh/laravel-dompdf
npm install
npm run build
Create files:

php artisan make:model Fruit -mcr
php artisan make:controller ReportController

PART 2: Migration
Open database/migrations/xxxx_create_fruits_table.php:

<?php

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

return new class extends Migration
{
public function up(): void
{
Schema::create('fruits', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('category');
$table->decimal('price', 8, 2);
$table->integer('stock');
$table->text('description')->nullable();
$table->boolean('is_available')->default(true);
$table->timestamps();
});
}

public function down(): void
{
    Schema::dropIfExists('fruits');
}

};
Run:

php artisan migrate
PART 3: Model
Open app/Models/Fruit.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Fruit extends Model
{
protected $fillable = [
'name',
'category',
'price',
'stock',
'description',
'is_available',
];

protected $casts = [
    'is_available' => 'boolean',
];

}
PART 4: Routes
Open routes/web.php and use this:

<?php

use App\Http\Controllers\FruitController;
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\ReportController;
use Illuminate\Support\Facades\Route;

Route::middleware('auth')->group(function () {
Route::get('/', function () {
return redirect()->route('fruits.index');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->name('dashboard');

Route::resource('fruits', FruitController::class);

Route::get('/reports', [ReportController::class, 'index'])->name('reports.index');
Route::get('/reports/pdf', [ReportController::class, 'exportPdf'])->name('reports.pdf');
Route::get('/reports/csv', [ReportController::class, 'exportCsv'])->name('reports.csv');

Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');

});

require DIR.'/auth.php';
Important: use reports.csv, not reports.excel.

PART 5: Fruit Controller
Open app/Http/Controllers/FruitController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Fruit;
use Illuminate\Http\Request;

class FruitController extends Controller
{
public function index()
{
$fruits = Fruit::latest()->paginate(10);
return view('fruits.index', compact('fruits'));
}

public function create()
{
    return view('fruits.create');
}

public function store(Request $request)
{
    $request->validate([
        'name' => 'required|string|max:255',
        'category' => 'required|string',
        'price' => 'required|numeric|min:0',
        'stock' => 'required|integer|min:0',
        'description' => 'nullable|string',
    ]);

    $data = $request->all();
    $data['is_available'] = $request->has('is_available') ? 1 : 0;

    Fruit::create($data);

    return redirect()->route('fruits.index')
        ->with('success', 'Fruit added successfully!');
}

public function show(Fruit $fruit)
{
    return view('fruits.show', compact('fruit'));
}

public function edit(Fruit $fruit)
{
    return view('fruits.edit', compact('fruit'));
}

public function update(Request $request, Fruit $fruit)
{
    $request->validate([
        'name' => 'required|string|max:255',
        'category' => 'required|string',
        'price' => 'required|numeric|min:0',
        'stock' => 'required|integer|min:0',
        'description' => 'nullable|string',
    ]);

    $data = $request->all();
    $data['is_available'] = $request->has('is_available') ? 1 : 0;

    $fruit->update($data);

    return redirect()->route('fruits.index')
        ->with('success', 'Fruit updated successfully!');
}

public function destroy(Fruit $fruit)
{
    $fruit->delete();

    return redirect()->route('fruits.index')
        ->with('success', 'Fruit deleted successfully!');
}

}
PART 6: Report Controller
Open app/Http/Controllers/ReportController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Fruit;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;

class ReportController extends Controller
{
public function index(Request $request)
{
$query = Fruit::query();

    if ($request->filled('category')) {
        $query->where('category', $request->category);
    }

    if ($request->filled('availability')) {
        $query->where('is_available', $request->availability);
    }

    $fruits = $query->get();
    $categories = Fruit::distinct()->orderBy('category')->pluck('category');

    return view('reports.index', compact('fruits', 'categories'));
}

public function exportPdf(Request $request)
{
    $query = Fruit::query();

    if ($request->filled('category')) {
        $query->where('category', $request->category);
    }

    if ($request->filled('availability')) {
        $query->where('is_available', $request->availability);
    }

    $fruits = $query->get();

    return Pdf::loadView('reports.pdf', compact('fruits'))
        ->download('fruit-report.pdf');
}

public function exportCsv(Request $request)
{
    $query = Fruit::query();

    if ($request->filled('category')) {
        $query->where('category', $request->category);
    }

    if ($request->filled('availability')) {
        $query->where('is_available', $request->availability);
    }

    $fruits = $query->get();

    $headers = [
        'Content-Type' => 'text/csv',
        'Content-Disposition' => 'attachment; filename="fruit-report.csv"',
    ];

    $callback = function () use ($fruits) {
        $file = fopen('php://output', 'w');

        fputcsv($file, ['Name', 'Category', 'Price/kg', 'Stock', 'Available', 'Description']);

        foreach ($fruits as $fruit) {
            fputcsv($file, [
                $fruit->name,
                $fruit->category,
                $fruit->price,
                $fruit->stock,
                $fruit->is_available ? 'Yes' : 'No',
                $fruit->description ?? 'N/A',
            ]);
        }

        fclose($file);
    };

    return response()->stream($callback, 200, $headers);
}

}


{{ $slot }}

Replace with this:


@hasSection('content')
@yield('content')
@else
{{ $slot ?? '' }}
@endif

Navigation
Open resources/views/layouts/navigation.blade.php.

Inside the left-side nav area, add or fix these links:

  • Fruits
  • Reports

fruits/index.blade.php
Create/open resources/views/fruits/index.blade.php:

@extends('layouts.app')

@section('content')

    <h2>Fruit Products</h2>
    <a href="{{%20route('fruits.create')%20}}">+ Add Fruit</a>


@if(session('success'))
    {{ session('success') }}
@endif

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Category</th>
            <th>Price/kg</th>
            <th>Stock</th>
            <th>Status</th>
            <th>Actions</th>
        </tr>
    </thead>

    <tbody>
        @forelse($fruits as $fruit)
            <tr>
                <td>{{ $fruit-&gt;name }}</td>
                <td>{{ $fruit-&gt;category }}</td>
                <td>₱{{ number_format($fruit-&gt;price, 2) }}</td>
                <td>{{ $fruit-&gt;stock }} kg</td>
                <td>
                    @if($fruit-&gt;is_available)
                        <span>Available</span>
                    @else
                        <span>Out of Stock</span>
                    @endif
                </td>
                <td>
                    <a href="{{%20route('fruits.show',%20$fruit)%20}}">View</a>
                    <a href="{{%20route('fruits.edit',%20$fruit)%20}}">Edit</a>


                        @csrf
                        @method('DELETE')

                        Delete

                </td>
            </tr>
        @empty
            <tr>
                <td colspan="6">No fruits yet. Add one!</td>
            </tr>
        @endforelse
    </tbody>
</table>

{{ $fruits-&gt;links() }}
Enter fullscreen mode Exit fullscreen mode

@endsection
fruits/create.blade.php
Create/open resources/views/fruits/create.blade.php:

@extends('layouts.app')

@section('content')

<h2>Add New Fruit</h2>

@if($errors-&gt;any())

        @foreach($errors-&gt;all() as $error)
            {{ $error }}
        @endforeach

@endif


    @csrf


        Fruit Name




        Category

            -- Select Category --

            @foreach(['Citrus', 'Berry', 'Tropical', 'Stone Fruit', 'Melon', 'Other'] as $cat)

                    {{ $cat }}

            @endforeach




        Price per kg (₱)




        Stock Quantity (kg)




        Description (Optional)
        {{ old('description') }}






            Available for Sale



    Add Fruit
    <a href="{{%20route('fruits.index')%20}}">Cancel</a>
Enter fullscreen mode Exit fullscreen mode

@endsection
fruits/edit.blade.php
Create/open resources/views/fruits/edit.blade.php:

@extends('layouts.app')

@section('content')

<h2>Edit - {{ $fruit-&gt;name }}</h2>

@if($errors-&gt;any())

        @foreach($errors-&gt;all() as $error)
            {{ $error }}
        @endforeach

@endif


    @csrf
    @method('PUT')


        Fruit Name




        Category

            @foreach(['Citrus', 'Berry', 'Tropical', 'Stone Fruit', 'Melon', 'Other'] as $cat)
                category) == $cat ? 'selected' : '' }}&gt;
                    {{ $cat }}

            @endforeach




        Price per kg (₱)




        Stock Quantity (kg)




        Description
        {{ old('description', $fruit-&gt;description) }}




            is_available) ? 'checked' : '' }}&gt;

            Available for Sale



    Update Fruit
    <a href="{{%20route('fruits.index')%20}}">Cancel</a>
Enter fullscreen mode Exit fullscreen mode

@endsection
fruits/show.blade.php
Create/open resources/views/fruits/show.blade.php:

@extends('layouts.app')

@section('content')

<h2>{{ $fruit-&gt;name }}</h2>


    <p><strong>Category:</strong> {{ $fruit-&gt;category }}</p>
    <p><strong>Price per kg:</strong> ₱{{ number_format($fruit-&gt;price, 2) }}</p>
    <p><strong>Stock:</strong> {{ $fruit-&gt;stock }} kg</p>
    <p><strong>Description:</strong> {{ $fruit-&gt;description ?? 'No description provided.' }}</p>

    <p>
        <strong>Status:</strong>

        @if($fruit-&gt;is_available)
            <span>Available</span>
        @else
            <span>Out of Stock</span>
        @endif
    </p>

    <p><strong>Added:</strong> {{ $fruit-&gt;created_at-&gt;format('F d, Y') }}</p>


<a href="{{%20route('fruits.edit',%20$fruit)%20}}">Edit</a>
<a href="{{%20route('fruits.index')%20}}">Back</a>
Enter fullscreen mode Exit fullscreen mode

@endsection
reports/index.blade.php
Create/open resources/views/reports/index.blade.php:

@extends('layouts.app')

@section('content')

<h2>Fruit Reports</h2>



        Filter by Category

            -- All Categories --

            @foreach($categories as $cat)

                    {{ $cat }}

            @endforeach




        Filter by Availability

            -- All --

                Available


                Out of Stock





        Filter
        <a href="{{%20route('reports.index')%20}}">Reset</a>




    <a href="{{%20route('reports.pdf',%20request()-&gt;query())%20}}">
        Export PDF
    </a>

    <a href="{{%20route('reports.csv',%20request()-&gt;query())%20}}">
        Export CSV
    </a>


<p>Showing <strong>{{ $fruits-&gt;count() }}</strong> result(s)</p>

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Category</th>
            <th>Price/kg</th>
            <th>Stock</th>
            <th>Status</th>
        </tr>
    </thead>

    <tbody>
        @forelse($fruits as $fruit)
            <tr>
                <td>{{ $fruit-&gt;name }}</td>
                <td>{{ $fruit-&gt;category }}</td>
                <td>₱{{ number_format($fruit-&gt;price, 2) }}</td>
                <td>{{ $fruit-&gt;stock }} kg</td>
                <td>
                    @if($fruit-&gt;is_available)
                        <span>Available</span>
                    @else
                        <span>Out of Stock</span>
                    @endif
                </td>
            </tr>
        @empty
            <tr>
                <td colspan="5">No results found.</td>
            </tr>
        @endforelse
    </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

@endsection

reports/pdf.blade.php

Create/open resources/views/reports/pdf.blade.php:

<!DOCTYPE html>







Fruit Report

<br>
body { font-family: Arial, sans-serif; font-size: 13px; }<br>
table { width: 100%; border-collapse: collapse; margin-top: 10px; }<br>
th, td { border: 1px solid #000; padding: 6px; }<br>
th { background-color: #eee; }<br>






Fruit Sales Report



Generated: {{ now()->format('F d, Y - h:i A') }}




































@forelse($fruits as $fruit)






















@empty










@endforelse




Name Category Price/kg Stock Status
{{ $fruit->name }} {{ $fruit->category }} ₱{{ number_format($fruit->price, 2) }} {{ $fruit->stock }} kg {{ $fruit->is_available ? 'Available' : 'Out of Stock' }}
No fruits found.



Top comments (0)