Introduction

Getting Started

Forte is a Blade parser and AST manipulation library. To get started using Forte, install it with Composer:

composer require fortephp/forte

Forte does not require additional configuration. To extend Blade without writing a parser extension or rewriter, use Enclaves. Enclaves apply built-in or community-provided transformations to selected templates.

#Parsing Your First Template

You can parse a Blade template by calling Forte::parse with the template string:

<?php
use Forte\Facades\Forte;
$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:

<?php
use Forte\Facades\Forte;
$template = <<<'BLADE'
<div class="container">
{{-- A comment --}}
@if ($show)
<p>Hello, {{ $name }}!</p>
@endif
</div>
BLADE;
$doc = Forte::parse($template);
$doc->render() === $template; // true

From there, you can inspect nodes, run XPath queries, or apply rewrites. Start with node identity and positions before moving into queries and transformations.

#The Parse Pipeline

Parsing happens in three phases, each feeding into the next.

#Lexer

The lexer scans source into a flat token stream. Specialized scanners recognize HTML elements, Blade directives, echoes, comments, PHP blocks, and raw PHP tags. Each token records its type and source offsets.

#Tree Builder

The tree builder assembles the token stream into Node objects. It pairs tags, matches directive blocks such as @if...@endif, resolves component slots, and nests children under their parents. When possible, malformed input becomes a partial tree with diagnostics on the 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.

<?php
use Forte\Facades\Forte;
use Forte\Rewriting\NodePath;
$original = Forte::parse('<div class="old">Hello</div>');
$modified = $original->rewriteWith(function (NodePath $path) {
if ($path->isTag('div')) {
$path->addClass('new');
}
});
$original->render(); // '<div class="old">Hello</div>'
$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:

  1. One or more visitors walk the tree, inspecting nodes and queuing operations (replace, remove, wrap, insert, etc.) through the NodePath API.
  2. Operations are committed as a batch, producing a new Document.
  3. 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:

  1. The DomMapper walks the AST and builds a DOMDocument where each Blade construct is represented as a namespaced element (e.g., forte:if, forte:echo).
  2. Standard DOMXPath evaluates the query expression against this DOM.
  3. Results are mapped back to AST nodes using data-forte-idx attributes 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:

  1. Extensions register trigger characters with the lexer (e.g., # for a hashtag extension).
  2. When the lexer encounters a trigger character, it invokes the extension's tokenizer, which may emit custom tokens.
  3. The tree builder consults registered tree extensions to convert custom tokens into custom node kinds.
  4. 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

Continue with these related Forte guides: