Laravel
PDF & Excel Export
Export data as PDF using barryvdh/laravel-dompdf and as Excel/CSV using maatwebsite/excel. Covers installation, Export class creation, collection binding, headings, and download/stream responses.
Install DomPDF: Add
barryvdh/laravel-dompdf via Composer. Laravel auto-discovers the service provider.terminal
BASH
composer require barryvdh/laravel-dompdf
# Optionally publish the config
php artisan vendor:publish --provider="Barryvdh\DomPDF\ServiceProvider"
Generate PDF from a Blade View: Use the
Pdf facade to load a view with data, then return it as a download or stream it inline to the browser.app/Http/Controllers/ReportController.php
PHP
<?php
namespace App\Http\Controllers;
use Barryvdh\DomPDF\Facade\Pdf;
use App\Models\Order;
class ReportController extends Controller
{
// Force browser to download the PDF
public function downloadPdf($id)
{
$order = Order::with('items.product', 'user')->findOrFail($id);
$pdf = Pdf::loadView('pdf.invoice', ['order' => $order])
->setPaper('a4', 'portrait');
return $pdf->download("invoice-{$order->id}.pdf");
}
// Stream PDF inline in the browser
public function streamPdf($id)
{
$order = Order::with('items.product', 'user')->findOrFail($id);
$pdf = Pdf::loadView('pdf.invoice', ['order' => $order])
->setPaper('a4', 'portrait');
return $pdf->stream("invoice-{$order->id}.pdf");
}
}
PDF Blade Template: Create a simple Blade view for DomPDF to render. Keep styles inline — DomPDF has limited CSS support.
resources/views/pdf/invoice.blade.php
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Invoice #{{ $order->id }}</title>
<style>
body { font-family: sans-serif; font-size: 13px; color: #333; }
table { width: 100%; border-collapse: collapse; margin-top: 16px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #f5f5f5; }
.total { text-align: right; font-weight: bold; margin-top: 12px; }
</style>
</head>
<body>
<h2>Invoice #{{ $order->id }}</h2>
<p>Customer: {{ $order->user->name }} <{{ $order->user->email }}></p>
<p>Date: {{ $order->created_at->format('d M Y') }}</p>
<table>
<thead>
<tr><th>#</th><th>Product</th><th>Qty</th><th>Price</th><th>Subtotal</th></tr>
</thead>
<tbody>
@foreach($order->items as $i => $item)
<tr>
<td>{{ $i + 1 }}</td>
<td>{{ $item->product->name }}</td>
<td>{{ $item->qty }}</td>
<td>Rp {{ number_format($item->price, 0, ',', '.') }}</td>
<td>Rp {{ number_format($item->price * $item->qty, 0, ',', '.') }}</td>
</tr>
@endforeach
</tbody>
</table>
<p class="total">Total: Rp {{ number_format($order->total_price, 0, ',', '.') }}</p>
</body>
</html>
Install Maatwebsite Excel: Add
maatwebsite/excel via Composer, then publish the config file.terminal
BASH
composer require maatwebsite/excel
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config
Create an Export Class: Generate an Export class with Artisan. Implement
FromCollection to supply data and WithHeadings to add a header row.terminal
BASH
php artisan make:export UsersExport --model=User
app/Exports/UsersExport.php
PHP
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class UsersExport implements
FromCollection,
WithHeadings,
WithMapping,
ShouldAutoSize
{
public function collection()
{
return User::select('id', 'name', 'email', 'created_at')
->orderBy('id')
->get();
}
public function headings(): array
{
return ['#', 'Full Name', 'Email Address', 'Registered At'];
}
public function map($user): array
{
return [
$user->id,
$user->name,
$user->email,
$user->created_at->format('d/m/Y H:i'),
];
}
}
Export with Constructor Filter: Pass parameters to the Export class constructor to filter data dynamically, e.g., by date range.
app/Exports/OrdersExport.php
PHP
<?php
namespace App\Exports;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
class OrdersExport implements FromQuery, WithHeadings, ShouldAutoSize
{
public function __construct(
protected string $from,
protected string $to
) {}
public function query()
{
return Order::with('user')
->whereBetween('created_at', [$this->from, $this->to])
->select('id', 'user_id', 'total_price', 'payment_status', 'created_at');
}
public function headings(): array
{
return ['Order ID', 'Customer', 'Total', 'Status', 'Date'];
}
}
Download Excel or CSV in Controller: Use the
Excel facade's download() method. Pass Xlsx::class, Csv::class, or Pdf::class as the writer type.app/Http/Controllers/ReportController.php
PHP
<?php
namespace App\Http\Controllers;
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\UsersExport;
use App\Exports\OrdersExport;
use Illuminate\Http\Request;
class ReportController extends Controller
{
// Download users as .xlsx
public function exportUsers()
{
return Excel::download(new UsersExport(), 'users.xlsx');
}
// Download users as .csv
public function exportUsersCsv()
{
return Excel::download(new UsersExport(), 'users.csv', \Maatwebsite\Excel\Excel::CSV);
}
// Download orders filtered by date range
public function exportOrders(Request $request)
{
$request->validate([
'from' => 'required|date',
'to' => 'required|date|after_or_equal:from',
]);
$filename = "orders-{$request->from}-to-{$request->to}.xlsx";
return Excel::download(
new OrdersExport($request->from, $request->to),
$filename
);
}
}
Export Routes: Register the export endpoints in
routes/web.php behind auth middleware.routes/web.php
PHP
use App\Http\Controllers\ReportController;
Route::middleware('auth')->prefix('export')->group(function () {
Route::get('/invoice/{order}', [ReportController::class, 'downloadPdf']);
Route::get('/invoice-view/{order}', [ReportController::class, 'streamPdf']);
Route::get('/users', [ReportController::class, 'exportUsers']);
Route::get('/users/csv', [ReportController::class, 'exportUsersCsv']);
Route::get('/orders', [ReportController::class, 'exportOrders']);
});