VOOZH about

URL: https://deepwiki.com/calevans/staticforge/10.2-extending-the-core

⇱ Extending the Core | calevans/staticforge | DeepWiki


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

Extending the Core

Purpose and Scope

This page covers strategies for extending StaticForge's core classes, adding custom event types, and safely modifying the processing pipeline. This documentation is for developers who need to:

  • Add new core services beyond the feature system
  • Create custom event types for feature extensibility
  • Extend or replace core processing components
  • Add support for new file types

For building features that use existing events, see Creating Custom Features. For architectural overview, see Architecture & Data Flow. For testing extended components, see Testing Strategy.


Core Services Architecture

StaticForge's core consists of seven primary services registered during bootstrap. Understanding these services is essential for knowing what can be extended and how.

Core Services Diagram


Sources: src/bootstrap.php234-254

Service Registration Points

Core services are registered in src/bootstrap.php using two container methods:

MethodPurposeLifecycle
stuff()Singleton services (lazy instantiation)Created on first access
add()Direct instance registrationImmediately available

Singleton Registration (Logger, Twig):


Direct Registration (Core Services):


Sources: src/bootstrap.php191-232


Adding Custom Event Types

StaticForge's event system allows features to fire custom events, enabling sub-ecosystems within features. The RSS Feed feature demonstrates this pattern by firing events that allow other features (like Podcast) to extend RSS feed generation.

Custom Event Lifecycle


Sources: src/Features/RssFeed/Services/RssFeedService.php180-218 content/development/events.md129-147

Implementing Custom Events

Step 1: Define event constants in your feature class:


Step 2: Fire events at extension points:

The RSS Feed feature fires RSS_BUILDER_INIT to allow configuration of the RSS builder object:

src/Features/RssFeed/Services/RssFeedService.php180-183

Step 3: Fire item-level events for per-item modification:

src/Features/RssFeed/Services/RssFeedService.php212-215

Step 4: Document your custom events:

Create documentation explaining:

  • Event name
  • When it fires
  • Data structure passed
  • Expected return values
  • Use cases

Sources: src/Features/RssFeed/Services/RssFeedService.php1-306

Custom Event Naming Convention

PatternExampleUsage
{FEATURE}_INITRSS_BUILDER_INITFeature initialization
{FEATURE}_{ACTION}_BUILDINGRSS_ITEM_BUILDINGDuring construction
{FEATURE}_{ACTION}_COMPLETERSS_GENERATION_COMPLETEAfter completion
{FEATURE}_COLLECT_{ITEM}COLLECT_MENU_ITEMSData collection

Extending Core Services

Core services can be extended using three strategies: decoration, inheritance, or complete replacement. Choose the strategy based on how much you need to change.

Strategy 1: Decoration (Recommended)

Wrap the core service to add functionality without modifying it.


Strategy 2: Inheritance

Extend core classes to override specific methods.


Sources: src/Core/FileDiscovery.php

Strategy 3: Complete Replacement

Create a new class implementing the same interface.



Extension Registry: Supporting New File Types

The ExtensionRegistry manages which file extensions can be processed. Features register extensions during their registration phase.

Extension Registration Flow


Sources: src/Core/ExtensionRegistry.php src/Features/MarkdownRenderer/Feature.php

Registering Custom Extensions

In your feature's register() method:


Key Points:

  • Register extensions in register() method before event listeners
  • Extension registry is queried by FileDiscovery during file scanning
  • Multiple features can register the same extension (first match wins)
  • Extensions must include the dot (.md, not md)

Sources: tests/Unit/Features/HtmlRenderer/FeatureTest.php70-74 src/Core/ExtensionRegistry.php

Extension Priority

When multiple features register the same extension, the first feature to register claims it. Control this through feature discovery priority:

Priority LevelLocationExecution Order
Highestsrc/Features/ (user)1st
MediumComposer packages2nd
Lowestvendor/eicc/staticforge/src/Features/3rd

Sources: src/Core/FeatureManager.php52-96


Service Container Patterns

The container provides dependency injection and configuration storage. Understanding its patterns is essential for extending core functionality.

Container Methods Reference

MethodPurposeReturn Type
stuff(string $key, callable $factory)Register lazy singletonvoid
add(string $key, object $instance)Register instancevoid
get(string $key)Retrieve servicemixed
has(string $key)Check existencebool
setVariable(string $key, mixed $value)Store configvoid
getVariable(string $key)Retrieve configmixed
updateVariable(string $key, mixed $value)Update configvoid

Singleton Pattern with stuff()

Use for services that should only be instantiated once:


Sources: src/bootstrap.php191-232

Instance Pattern with add()

Use for services that need immediate configuration:


Sources: src/bootstrap.php234-254

Configuration Storage

Store computed values and configuration:


Sources: src/bootstrap.php130-171


Feature Priority System

The feature priority system controls execution order across three dimensions: discovery priority, event priority, and feature dependencies.

Feature Discovery Priority


Sources: src/Core/FeatureManager.php52-96

Event Priority Within Lifecycle Stages

Event priorities control execution order within a single event:


Key Priority Ranges:

RangePurposeExamples
0-50First responders, data creationCategoryIndex (50)
100-150Standard processingMenuBuilder (100), Tags (150)
200-250Data transformationCategories (250)
900-999Cleanup and finalizationUpload features (900)

Sources: content/development/architecture.md103-113

Controlling Feature Execution Order

Method 1: Set priority in eventListeners array:


Method 2: Override with manual registration:


Sources: content/development/features.md84-93


Best Practices for Core Extensions

1. Prefer Decoration Over Inheritance

Why: Decoration maintains the original interface while adding functionality, reducing coupling.

Example:


2. Use Custom Events for Feature Extension Points

Why: Allows other features to extend your feature without modifying its code.

Pattern:


Sources: src/Features/RssFeed/Services/RssFeedService.php180-218

3. Document Service Dependencies

Why: Makes it clear what services your extension requires.

Pattern:


4. Use Feature Priority for Ordering

Why: Avoids race conditions and ensures data availability.

Rule of thumb:

  • If you create data other features need: Priority 50-100
  • If you transform data: Priority 150-250
  • If you consume data: Priority 200-999

Example:


Sources: content/development/architecture.md103-113

5. Store Feature Data in Container

Why: Makes data accessible to templates and other features.

Pattern:


6. Handle Missing Services Gracefully

Why: Extensions may run in different configurations.

Pattern:


7. Test Custom Events

Why: Ensures your extension points work as expected.

Pattern:


Sources: tests/Unit/Features/HtmlRenderer/FeatureTest.php


Common Extension Scenarios

Adding a New Content Type Processor

Scenario: Add support for AsciiDoc files (.adoc)

Implementation:

  1. Create feature class:

Sources: tests/Unit/Features/HtmlRenderer/FeatureTest.php70-74

Creating a Custom Event Lifecycle

Scenario: Add a PDF generation phase after HTML rendering

Implementation:

  1. Extend FileProcessor to add new event:

  1. Register in bootstrap:

  1. Create feature to handle event:

Adding Global Template Variables

Scenario: Make computed data available to all templates

Implementation:


Sources: content/development/architecture.md159-172


Summary

Extending StaticForge's core requires understanding:

  1. Service Architecture - The seven core services and their registration patterns
  2. Custom Events - How to fire events for feature extension points
  3. Extension Registry - Adding support for new file types
  4. Container Patterns - Singleton vs. instance registration
  5. Priority System - Controlling execution order across discovery, events, and features
  6. Best Practices - Decoration over inheritance, graceful degradation, testing

Key Principles:

  • Extend through decoration rather than modification
  • Use custom events to create extension points
  • Control execution order with priorities
  • Store data in container for cross-feature communication
  • Test extensions with the same rigor as core features

For implementing features using existing hooks, see Creating Custom Features. For architectural patterns, see Architecture & Data Flow.

Refresh this wiki

On this page