Excel & PDF Reports
01 Choosing an Excel library
Solution and explanation
- Maatwebsite/Laravel-Excel is the common Laravel integration built on PhpSpreadsheet.
- PhpSpreadsheet gives lower-level control, while Spatie Simple Excel is useful for memory-efficient streaming of simple, very large files.
// Common Laravel choice
composer require maatwebsite/excel
// Lower-level spreadsheet engine
composer require phpoffice/phpspreadsheet
Compare the libraries for a formatted monthly report and a two-million-row CSV export.
Quick check
Which statement is correct?
02 Installing Excel and PDF packages
Solution and explanation
- Install only the packages the application needs and commit composer.json plus composer.lock.
- DomPDF renders controlled Blade HTML without requiring Chromium.
composer require maatwebsite/excel barryvdh/laravel-dompdf
composer show maatwebsite/excel
composer show barryvdh/laravel-dompdf
Install in a feature branch and confirm Composer selected versions compatible with the project PHP version.
Quick check
Which statement is correct?
03 Creating a Laravel Excel export
Solution and explanation
- An export class describes the rows and headings independently from the HTTP controller.
- Concerns compose features without turning the controller into report logic.
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
final class UsersExport implements FromQuery, WithHeadings {
public function query() { return User::query()->select('id','name','email','created_at'); }
public function headings(): array { return ['ID','Name','Email','Created At']; }
}
Generate UsersExport and export only columns approved for the report.
Quick check
Which statement is correct?
04 Exporting large datasets safely
Solution and explanation
- Avoid loading a massive dataset with get().
- Query-based or generator-based exports, chunk reading, queues and temporary object storage keep HTTP memory stable.
final class JobsExport implements FromQuery, ShouldQueue {
public function query() {
return Job::query()->published()->select('id','title','company_id');
}
}
Test the export with 100,000 factory records and monitor peak memory.
Quick check
Which statement is correct?
05 Downloading an Excel report
Solution and explanation
- The controller authorizes the report, constructs the export and returns Excel::download.
- Filters should be validated and passed explicitly.
use Maatwebsite\Excel\Facades\Excel;
public function excel(ReportFilterRequest $request) {
$this->authorize('exportUsers');
return Excel::download(new UsersExport($request->validated()), 'users-report.xlsx');
}
Protect a candidate export so only an authorized owner can download it.
Quick check
Which statement is correct?
06 Choosing a PDF renderer
Solution and explanation
- DomPDF converts conservative HTML/CSS to PDF and works well for invoices and reports.
- Spatie Laravel PDF or Browsershot uses Chromium when exact modern CSS rendering is essential.
use Barryvdh\DomPDF\Facade\Pdf;
$pdf = Pdf::loadView('reports.users-pdf', ['users'=>$users]);
return $pdf->download('users-report.pdf');
Choose a renderer for an ATS resume and another for a pixel-perfect dashboard printout.
Quick check
Which statement is correct?
07 Building a PDF Blade template
Solution and explanation
- A PDF view should have deterministic dimensions, embedded print-safe CSS, escaped values and a layout supported by the selected renderer.
<!doctype html>
<html><head><style>
table{width:100%;border-collapse:collapse}
th,td{border:1px solid #ddd;padding:8px;text-align:left}
</style></head><body>
<h2>Users List</h2>
@foreach($users as $user) <p>{{ $user->name }} — {{ $user->email }}</p> @endforeach
</body></html>
Render malicious-looking user text and confirm Blade escapes it in the PDF HTML.
Quick check
Which statement is correct?
08 Defining secure report routes
Solution and explanation
- Use named controller routes protected by authentication, authorization and appropriate throttling.
- Keep report creation out of anonymous GET endpoints when it is expensive or sensitive.
Route::middleware(['auth','throttle:reports'])->group(function(){
Route::get('/reports/users.xlsx',[ReportController::class,'excel'])->name('reports.users.excel');
Route::get('/reports/users.pdf',[ReportController::class,'pdf'])->name('reports.users.pdf');
});
Add policy checks and a feature test proving an ordinary student receives 403.
Quick check
Which statement is correct?
