›
byrcsc/laravel-checklist · 1.x
Build ordered checklist data for rendering and query stored operational metrics without recomputing history.
An export flattens one checklist into ordered data you can hand to a Blade view, a JSON response, or a PDF renderer. It carries the recorded answers, evidence references, scores, and chain status. Reports and query scopes summarize many runs from the results already stored on them.
use ByRcsc\LaravelChecklist\Models\Checklist;
$checklist = Checklist::query()
->withExportRelations()
->findOrFail($id);
$export = $checklist->toExport();
$data = $export->toArray();
$json = json_encode($export, JSON_THROW_ON_ERROR);withExportRelations() loads the frozen template, ordered structure,
responses, evidence, people, subject, schedule, and action count. The export
then verifies the audit chain with one streamed history walk.
The top level contains checklist and template identity, status, subject, assignee, timestamps, score fields, root answers, nested sections, review, and chain status.
Each answer contains the frozen item fields, answer state, value, note,
applicability, answerer, time, evidence, and signatures. Hidden answers remain
present with is_applicable: false.
Evidence entries contain disk and path, not a public URL. Generate an
authorized URL at render time:
use Illuminate\Support\Facades\Storage;
$url = Storage::disk($reference->disk)
->temporaryUrl($reference->path, now()->addMinutes(10));$export->signatures() collects every signature from root and nested answers
for renderers that place signatures in a separate section.
The package does not generate PDF files. Pass the array to Blade, a JSON API, or your chosen PDF renderer.
The package does not depend on a PDF renderer. Install one, then pass the export to a view:
composer require barryvdh/laravel-dompdfuse Barryvdh\DomPDF\Facade\Pdf;
use ByRcsc\LaravelChecklist\Models\Checklist;
$checklist = Checklist::query()->withExportRelations()->findOrFail($id);
return Pdf::loadView('checklists.pdf', ['export' => $checklist->toExport()])
->download("checklist-{$id}.pdf");The view reads the export's public properties. Sections nest, so the section and answer partials each include themselves for children:
{{-- resources/views/checklists/pdf.blade.php --}}
<h1>{{ $export->templateName }} <small>v{{ $export->templateVersion }}</small></h1>
<p>
Subject: {{ $export->subject ?? 'None' }}<br>
Assigned to: {{ $export->assignee ?? 'Nobody' }}
</p>
<p>
Status: {{ $export->status->value }}
@if ($export->score !== null)
(score: {{ number_format($export->score * 100, 1) }}%)
@if ($export->passed !== null)
({{ $export->passed ? 'passed' : 'failed' }})
@endif
@endif
</p>
@if ($export->criticalFailed)
<p><strong>A critical item failed.</strong></p>
@endif
@include('checklists.partials.answers', ['answers' => $export->answers])
@foreach ($export->sections as $section)
@include('checklists.partials.section', ['section' => $section])
@endforeach
@if ($export->signatures())
<h2>Signatures</h2>
@foreach ($export->signatures() as $signature)
<img src="{{ Storage::disk($signature->disk)->path($signature->path) }}" width="240">
@endforeach
@endif
@if ($export->review->reviewed)
<p>
Reviewed by {{ $export->review->reviewer }}.
Outcome: {{ $export->review->outcome }}.
</p>
@endif
<p>
Audit chain: {{ $export->chain->intact ? 'verified' : 'BROKEN: ' . $export->chain->reason }}
({{ $export->chain->actions }} actions)
</p>{{-- resources/views/checklists/partials/section.blade.php --}}
<h2>{{ $section->name }}</h2>
@include('checklists.partials.answers', ['answers' => $section->answers])
@foreach ($section->sections as $child)
@include('checklists.partials.section', ['section' => $child])
@endforeach{{-- resources/views/checklists/partials/answers.blade.php --}}
@foreach ($answers as $answer)
<p @class(['not-applicable' => ! $answer->isApplicable])>
{{ $answer->label }}:
{{ $answer->isAnswered ? json_encode($answer->value) : 'Not answered' }}
@unless ($answer->isApplicable) <em>(not applicable)</em> @endunless
@if ($answer->note)<br><em>{{ $answer->note }}</em>@endif
@foreach ($answer->evidence as $file)
<br><img src="{{ Storage::disk($file->disk)->path($file->path) }}" width="200">
@endforeach
</p>
@endforeachStorage::disk()->path() reads the file from local disk, which suits a
renderer running on the same machine. Use temporaryUrl() as shown above when
the evidence disk is remote.
Checklist::query()->pending();
Checklist::query()->inProgress();
Checklist::query()->completed();
Checklist::query()->reviewed();
Checklist::query()->overdue();
Checklist::query()->forSubject($vehicle);
Checklist::query()->forAssignee($driver);
Checklist::query()->forTemplate($template);
Checklist::query()->completedBetween($from, $to);overdue() returns only pending and in-progress work whose due date has
passed. Finished work may be late, but it is no longer overdue.
use ByRcsc\LaravelChecklist\Reporting\Reports;
$rates = Reports::completionRate($template);
$averages = Reports::averageScore($template);
$failed = Reports::mostFailedItems(limit: 20);
$overdue = Reports::overdueByAssignee();
$critical = Reports::criticalFailures($template);Completion and average score return one row per template version. Average score uses the value stored at submission.
Most-failed items groups by lineage across versions and excludes not-applicable answers. It scans applicable answered responses in chunks because select failure depends on item configuration and cannot be expressed as one portable SQL predicate.
Reports return data objects with public readonly properties and toArray().
They do not cache or materialize summary tables.