VOOZH about

URL: https://deepwiki.com/calevans/staticforge/3-core-architecture

⇱ Core Architecture | calevans/staticforge | DeepWiki


Loading...
Last indexed: 11 February 2026 (5f6a2a)
Menu

Core Architecture

Purpose and Scope

This document describes StaticForge's foundational architecture: the bootstrap process, core service registration, dependency injection container, event management system, and file processing pipeline. These components form the infrastructure layer upon which all features and functionality are built.

For configuration management details, see Configuration System. For content processing specifics, see Content Management. For template rendering, see Template System. For the feature plugin architecture, see Feature System.


System Overview

StaticForge implements a three-layer architecture with dependency injection, event-driven processing, and a modular feature system.

Diagram: Core System Components


Sources: src/bootstrap.php1-258 composer.json38-42


Bootstrap Process

The bootstrap process initializes the application by loading dependencies, parsing configuration, and registering core services. This occurs exactly once per CLI invocation.

Diagram: Bootstrap Sequence


Sources: src/bootstrap.php1-258 src/bootstrap.php23-44 src/bootstrap.php60-77 src/bootstrap.php79-109

Autoloader Resolution

Bootstrap attempts to load the Composer autoloader from multiple locations to support both library installation and development contexts:

PathContext
__DIR__ . '/../vendor/autoload.php'Development (project root)
__DIR__ . '/../../../autoload.php'Library installation (vendor/eicc/staticforge/)
getcwd() . '/vendor/autoload.php'Working directory fallback

Sources: src/bootstrap.php26-39

Environment Variable Loading

The .env file is loaded using Dotenv::createUnsafeMutable() which populates $_ENV superglobal. Variables are then copied to the Container for backward compatibility. The system sets sensible defaults before loading:

SOURCE_DIR = content
TEMPLATE_DIR = templates
OUTPUT_DIR = public
LOG_DIR = logs
LOG_LEVEL = INFO
TEMPLATE = staticforce

Sources: src/bootstrap.php60-127 .env.example1-42

Path Normalization

All directory paths are normalized to absolute paths using the $normalizePath closure. This handles:

  • Relative paths: prepend $appRoot
  • Absolute Unix paths: starting with /
  • Windows paths: matching [a-zA-Z]:\\
  • Stream wrappers: containing :// (e.g., vfs:// for testing)

Sources: src/bootstrap.php95-109

Site Configuration Loading

The optional siteconfig.yaml file is loaded via Symfony's YAML parser and stored in the Container as site_config. If parsing fails, a RuntimeException is thrown with the parse error details.

Sources: src/bootstrap.php143-168


Dependency Injection Container

The Container class (from eicc/utils) provides service registration and variable storage. It supports two registration methods:

Service Registration Methods

MethodBehaviorUse Case
stuff($key, $value)Singleton: resolves once, caches resultStateful services (Logger, Twig)
add($key, $value)Direct storage: returns exact valuePre-instantiated objects

Diagram: Container Service Registration


Sources: src/bootstrap.php191-205 src/bootstrap.php208-232 src/bootstrap.php235-254

Variable Storage

Variables are stored using setVariable($key, $value) and retrieved using getVariable($key). The Container maintains a separate variable namespace from services. Variables can be updated using updateVariable($key, $value).

Sources: src/bootstrap.php130-141 src/bootstrap.php171


Core Services

StaticForge registers seven core services during bootstrap, each providing specific functionality to the system.

EventManager

Class: EICC\StaticForge\Core\EventManager

The EventManager implements a priority-based event bus using the on() and fire() methods.

Key Methods:

  • on(string $event, callable $callback, int $priority = 500): Register event listener
  • fire(string $event, array $data = []): Dispatch event to registered listeners
  • Priority range: 0 (earliest) to 999 (latest)

Event listeners receive (Container $container, array $data) and must return array $data.

Sources: src/bootstrap.php235-236

FeatureManager

Class: EICC\StaticForge\Core\FeatureManager

The FeatureManager discovers and loads features from three locations with priority-based override:

PriorityLocationUse Case
HIGHESTsrc/Features/User features (override library)
MEDIUMComposer packages with extra.staticforge.featureThird-party features
LOWESTvendor/eicc/staticforge/src/Features/Library features

Features are instantiated and their register() method is called with EventManager and Container.

Sources: src/bootstrap.php241-242

ExtensionRegistry

Class: EICC\StaticForge\Core\ExtensionRegistry

The ExtensionRegistry maintains a map of file extensions to handler features. Renderer features register extensions via:

$extensionRegistry->register('.md', 'MarkdownRenderer')
$extensionRegistry->register('.html', 'HtmlRenderer')

The canProcess($extension) method determines if a file type can be handled.

Sources: src/bootstrap.php244-245

AssetManager

Class: EICC\StaticForge\Core\AssetManager

The AssetManager collects CSS and JavaScript assets from features for injection into templates. Features register assets via:

  • registerStyle($url, $position = 'head')
  • registerScript($url, $position = 'footer')
  • registerInlineScript($code, $position = 'footer')

Sources: src/bootstrap.php238-239

FileDiscovery

Class: EICC\StaticForge\Core\FileDiscovery

FileDiscovery scans content directories, parses frontmatter, and generates URLs. The discoverFiles() method returns an array of file metadata stored in Container as discovered_files.

Sources: src/bootstrap.php247-248

FileProcessor

Class: EICC\StaticForge\Core\FileProcessor

FileProcessor orchestrates the build pipeline by firing events at key stages. The processFiles() method iterates discovered files and triggers the rendering loop events.

Sources: src/bootstrap.php253-254

ErrorHandler

Class: EICC\StaticForge\Core\ErrorHandler

ErrorHandler provides centralized error reporting and logging. It is registered but not invoked during normal bootstrap.

Sources: src/bootstrap.php250-251


Event Lifecycle

The build process follows a deterministic event sequence with priority-based listener execution.

Diagram: Event Firing Sequence


Sources: content/development/events.md31-61 content/development/architecture.md71-102

Event Priority Table

EventTypical PriorityCommon Listeners
CREATE500Feature initialization
PRE_GLOB500Pre-discovery setup
POST_GLOB50-250CategoryIndex (50), MenuBuilder (100), Categories (250)
PRE_RENDER500Metadata enrichment
RENDER500MarkdownRenderer, HtmlRenderer
POST_RENDER500Asset injection, analytics
POST_LOOP90-100RSSFeed (90), Sitemap, TemplateAssets (100)
DESTROY500Cleanup

Sources: content/development/architecture.md103-116


File Discovery Process

FileDiscovery scans directories, parses frontmatter, filters files, and generates URLs before any rendering occurs.

Diagram: FileDiscovery Pipeline


Sources: content/guide/configuration.md346-368 content/development/architecture.md29-62

URL Generation Algorithm

URLs are constructed through a multi-step transformation:

  1. Remove extension: content/blog/post.mdblog/post
  2. Add .html: blog/postblog/post.html
  3. Apply category: If category: tech, insert category subdirectory → tech/post.html
  4. Prepend base URL: https://example.com/tech/post.html

Sources: content/guide/configuration.md346-397

Discovered Files Data Structure

Each entry in discovered_files contains:


This array is stored in Container and becomes the "single source of truth" for the build process.

Sources: content/development/architecture.md38-58


Build Pipeline Integration

The complete build pipeline integrates all core components through the FileProcessor.

Diagram: Complete Build Pipeline


Sources: content/development/architecture.md68-102 README.md57-64

Container State Evolution

The Container's state evolves throughout the build:

StageContainer Contents
BootstrapServices, variables, configuration
Discovery+ discovered_files array
POST_GLOB+ Feature-generated data (menus, tag lists)
Rendering Loop+ Per-file rendering context
POST_LOOP+ Generated artifact paths

Sources: src/bootstrap.php129-171


Service Lifecycle

Services registered in the Container follow specific initialization and usage patterns.

Singleton Services (Lazy Initialization)

Services registered via stuff() use closures that are resolved on first access:


The closure executes once when $container->get('logger') is first called. Subsequent calls return the cached instance.

Sources: src/bootstrap.php191-205

Twig Environment Configuration

The Twig service uses FilesystemLoader with two paths:

  1. Base template directory: $TEMPLATE_DIR (e.g., templates/)
  2. Active template: $TEMPLATE_DIR/$TEMPLATE/ (e.g., templates/staticforce/)

Configuration options:

  • debug: true
  • strict_variables: false
  • autoescape: 'html'
  • cache: false

Sources: src/bootstrap.php208-232

Direct Service Registration

Services registered via add() are pre-instantiated and stored directly:


These services are constructed during bootstrap and passed the Container for dependency access.

Sources: src/bootstrap.php235-254


Template Resolution Priority

The system determines which template to use through a three-tier resolution hierarchy:

  1. siteconfig.yaml site.template (highest priority)
  2. $_ENV['TEMPLATE'] from .env file
  3. 'staticforce' hardcoded default

This resolution occurs during bootstrap and stores the final value in Container as TEMPLATE.

Sources: src/bootstrap.php173-187


Summary

StaticForge's core architecture implements a clean separation between infrastructure (bootstrap, container, events) and application logic (features, processing). The bootstrap process establishes a fully-configured Container with seven core services. The EventManager enables loose coupling between features. FileDiscovery creates a single source of truth for site structure. FileProcessor orchestrates the build through deterministic event firing. This architecture enables extensibility without modifying core code—features simply register event listeners to participate in the build pipeline.

Sources: src/bootstrap.php1-258 composer.json1-60 content/development/architecture.md1-247