Introduction
Getting Started
Forte is a Blade parser and AST manipulation library. To get started using Forte, install it with Composer:
1composer require fortephp/forte
Forte does not require any extra steps or configuration. If you want to extend Blade's features without writing your own parser extensions or rewriters, see the Enclaves article. Enclaves let you apply built-in rewriters (like conditional elements and foreach attributes) or community-provided transformations to your templates.
#Parsing Your First Template
You can parse a Blade template by calling Forte::parse with the template string:
1<?php
2
3use Forte\Facades\Forte;
4
5$document = Forte::parse('Hello, {{ $name }}');
You will receive an instance of Forte\Ast\Document\Document, which gives you a single entry point for querying, traversing, rewriting, and rendering templates.
#Inspecting and Rendering
The fastest way to understand Forte is to parse a template and render it back out. Unmodified documents preserve the original source exactly:
1<?php
2
3use Forte\Facades\Forte;
4
5$template = <<<'BLADE'
6<div class="container">
7 {{-- A comment --}}
8 @if ($show)
9 <p>Hello, {{ $name }}!</p>
10 @endif
11</div>
12BLADE;
13
14$doc = Forte::parse($template);
15
16$doc->render() === $template; // true
From there, you can inspect nodes, run XPath queries, or apply rewrites. The rest of this article introduces the main concepts behind these workflows.
#The Parse Pipeline
Parsing happens in three phases, each feeding into the next.
#Lexer
The lexer scans the source string and emits a flat stream of tokens. Specialized scanners handle HTML elements, Blade directives, echoes ({{ }}, {!! !!}, {{{ }}}), HTML and Blade comments, PHP blocks (@php...@endphp), and raw PHP tags (<?php ?>). Each token records a type, a start offset, and an end offset.
#Tree Builder
The tree builder reads the token stream and assembles it into a tree of Node objects. It pairs opening and closing tags, matches directive blocks (@if...@endif), resolves component slots, and nests children under their parents. Malformed input is recovered into a partial tree where possible, and diagnostics are recorded on the resulting document.
#Document
The resulting tree is wrapped in a Document instance. The document is the public entry point for everything else, including querying, iterating, rewriting, and rendering.
#Node Indices
Every node in the tree gets a numeric index via $node->index(). This is the node's position in the document's internal flat array. Indices are stable within a single document instance but will change after rewriting.
#Immutability
Documents are immutable. All mutation methods, such as apply, rewrite, rewriteWith, return a new Document. The original is never modified.
1<?php
2
3use Forte\Facades\Forte;
4use Forte\Rewriting\NodePath;
5
6$original = Forte::parse('<div class="old">Hello</div>');
7
8$modified = $original->rewriteWith(function (NodePath $path) {
9 if ($path->isTag('div')) {
10 $path->addClass('new');
11 }
12});
13
14$original->render(); // '<div class="old">Hello</div>'
15$modified->render(); // '<div class="old new">Hello</div>'
The $original document is unchanged after the rewrite. This makes it safe to hold references to earlier versions while building transformation chains.
#Rewriting
Mutation works through a visitor-based system:
- One or more visitors walk the tree, inspecting nodes and queuing operations (replace, remove, wrap, insert, etc.) through the
NodePathAPI. - Operations are committed as a batch, producing a new
Document. - Multiple rewriters can be composed into a
RewritePipeline, where each rewriter operates on the document produced by the previous one.
Because operations are batched, Forte avoids creating excessive intermediate documents when a rewriter touches many nodes.
#XPath
Forte supports XPath querying by converting the AST into a DOM tree:
- The
DomMapperwalks the AST and builds aDOMDocumentwhere each Blade construct is represented as a namespaced element (e.g.,forte:if,forte:echo). - Standard
DOMXPathevaluates the query expression against this DOM. - Results are mapped back to AST nodes using
data-forte-idxattributes that reference each node's index.
This means you can use familiar XPath 1.0 syntax to search Blade templates without manually traversing the tree.
#Extensions
The extension system hooks into the parse pipeline at multiple points:
- Extensions register trigger characters with the lexer (e.g.,
#for a hashtag extension). - When the lexer encounters a trigger character, it invokes the extension's tokenizer, which may emit custom tokens.
- The tree builder consults registered tree extensions to convert custom tokens into custom node kinds.
- Custom nodes participate in DOM mapping, so they are queryable with XPath just like built-in nodes.
Extensions are registered through ParserOptions and managed by an ExtensionRegistry that handles dependency resolution and conflict detection.
#See also
- Documents: Full API for working with parsed documents
- Basic Nodes: Learn about the node types in the AST
- Rewriters: The visitor pattern and NodePath API
- Enclaves: Extend Blade with isolated compilation environments
- Parser Extensions: Teach the parser new syntax