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:

  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