Querying
Diagnostics
When Forte encounters malformed syntax during parsing (unclosed echoes, unterminated comments, or invalid constructs), it records diagnostics rather than throwing exceptions. You can inspect these diagnostics to detect and report template errors.
#Accessing Diagnostics
The diagnostics method on a Document returns a DiagnosticBag containing all errors and warnings from both the lexer and parser stages. The hasErrors method provides a quick boolean check:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('{{ $unclosed');
$doc->hasErrors(); // true
$doc->diagnostics()->count(); // 1
A well-formed template produces an empty bag:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('<div>{{ $name }}</div>');
$doc->hasErrors(); // false
$doc->diagnostics()->isEmpty(); // true
#The Diagnostic Object
Each diagnostic is a readonly value object with a severity level, message, source offset range, and origin. You can inspect these properties directly:
<?php
use Forte\Diagnostics\DiagnosticSeverity;
use Forte\Facades\Forte;
$doc = Forte::parse('{{ $unclosed');
$diag = $doc->diagnostics()->first();
$diag->severity; // DiagnosticSeverity::Error
$diag->source; // "lexer"
$diag->code; // "UnexpectedEof"
$diag->start; // 12
$diag->end; // 13
$diag->length(); // 1
Convenience methods check the severity level without comparing enum values:
<?php
$diag->isError(); // true
$diag->isWarning(); // false
$diag->isInfo(); // false
$diag->isHint(); // false
Diagnostics implement Stringable, so you can cast them directly for logging or display:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('{{-- unclosed comment');
$diag = $doc->diagnostics()->first();
$output = (string) $diag; // "error(21-22): [UnclosedComment] Unclosed comment [lexer]"
#Filtering by Severity
DiagnosticBag provides dedicated methods to filter by severity level. Each returns a Laravel Collection:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('{{ $unclosed');
$bag = $doc->diagnostics();
$bag->errors()->count(); // 1
$bag->warnings()->count(); // 0
$bag->info()->count(); // 0
$bag->hints()->count(); // 0
Use atLeast to get all diagnostics at or above a given severity. Since errors have the highest priority (value 1), filtering at the warning level includes both warnings and errors:
<?php
use Forte\Diagnostics\DiagnosticSeverity;
use Forte\Facades\Forte;
$doc = Forte::parse('{{ $unclosed');
$bag = $doc->diagnostics();
$bag->atLeast(DiagnosticSeverity::Warning)->count(); // 1
$bag->atLeast(DiagnosticSeverity::Error)->count(); // 1
#Querying Diagnostics
You can narrow diagnostics by their origin using fromSource. Forte tags diagnostics as either "lexer" or "parser" depending on which stage produced them:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('{{ $unclosed');
$bag = $doc->diagnostics();
$bag->fromSource('lexer')->count(); // 1
$bag->fromSource('parser')->count(); // 0
To find diagnostics within a specific byte range of the source, use inRange:
<?php
$bag->inRange(0, 20); // Collection<Diagnostic>
The bag also supports first, last, and arbitrary filtering with filter:
<?php
$bag->first(); // ?Diagnostic
$bag->last(); // ?Diagnostic
$bag->filter(fn ($d) => $d->code === 'UnexpectedEof'); // Collection<Diagnostic>
#Sorting and Formatting
sortByPosition orders diagnostics by their start offset, and sortBySeverity orders them by severity (errors first):
<?php
$bag->sortByPosition();
$bag->sortBySeverity();
The format method produces a human-readable summary. When you pass the original source string, it includes line and column numbers:
<?php
use Forte\Facades\Forte;
$template = '{{ $unclosed';
$doc = Forte::parse($template);
$bag = $doc->diagnostics();
$bag->format($template); // "1:13 error(12-13): [UnexpectedEof] ..."
An empty bag formats to a simple message:
<?php
use Forte\Facades\Forte;
$doc = Forte::parse('<div>Hello</div>');
$doc->diagnostics()->format(); // "No diagnostics."
#DiagnosticSeverity
The DiagnosticSeverity enum defines four levels, ordered from most to least severe:
| Level | Value | Label |
|---|---|---|
Error |
1 |
"error" |
Warning |
2 |
"warning" |
Info |
3 |
"info" |
Hint |
4 |
"hint" |
The label method returns a lowercase string representation, and isAtLeast compares severity levels (lower value means higher severity):
<?php
use Forte\Diagnostics\DiagnosticSeverity;
DiagnosticSeverity::Error->label(); // "error"
DiagnosticSeverity::Warning->label(); // "warning"
DiagnosticSeverity::Error->isAtLeast(DiagnosticSeverity::Warning); // true
DiagnosticSeverity::Warning->isAtLeast(DiagnosticSeverity::Error); // false
DiagnosticSeverity::Warning->isAtLeast(DiagnosticSeverity::Warning); // true
#See also
- Traversal: Navigate and query the document tree
- XPath Queries: Query documents with XPath expressions
- Documents: The Document class that provides
diagnostics()andhasErrors()