Overview
ForkBB is built on a Model-View-Controller (MVC) architecture with a powerful dependency injection container at its core. The framework emphasizes separation of concerns, testability, and extensibility.
Core Components
Container Service container for dependency injection
Router URL routing and link generation
Models Data layer and business logic
Controllers Request handling and orchestration
Views Template rendering system
Events Event-driven architecture
Application Bootstrap Flow
The application starts from bootstrap.php, which initializes the framework and handles requests:
// 1. Load dependencies
$loader = require __DIR__ . '/../vendor/autoload.php' ;
$errorHandler = new ErrorHandler ();
// 2. Initialize container with configuration
if ( \ is_file ( __DIR__ . '/config/main.php' )) {
$c = new Container ( include __DIR__ . '/config/main.php' );
} elseif ( \ is_file ( __DIR__ . '/config/install.php' )) {
$c = new Container ( include __DIR__ . '/config/install.php' );
} else {
throw new RuntimeException ( 'Application is not configured' );
}
// 3. Setup error handling
$errorHandler -> setContainer ( $c );
\ForkBB\ _init ( $c );
// 4. Configure URLs (https/http detection)
if ( ! empty ( $_SERVER [ 'HTTPS' ]) && 'off' !== \ strtolower ( $_SERVER [ 'HTTPS' ])) {
$c -> BASE_URL = \ str_replace ( 'http://' , 'https://' , $c -> BASE_URL );
} else {
$c -> BASE_URL = \ str_replace ( 'https://' , 'http://' , $c -> BASE_URL );
}
// 5. Dispatch bootstrap event
$c -> dispatcher = new EventDispatcher ( $c );
$event = new Event ( 'bootstrap:start' );
$event -> controllers = [ 'Primary' , 'Routing' ];
$c -> dispatcher -> dispatch ( $event );
// 6. Execute controllers to get page
foreach ( $event -> controllers as $controller ) {
$page = $c -> { $controller };
if ( $page instanceof Page ) {
break ;
}
}
// 7. Calculate online users
if ( null !== $page -> onlinePos ) {
$c -> Online -> calc ( $page );
}
// 8. Prepare page for rendering
if ( null !== $page -> nameTpl ) {
$page -> prepare ();
}
// 9. Close database connection
if ( $c -> isInit ( 'DB' )) {
if ( $c -> DB -> inTransaction ()) {
$c -> DB -> commit ();
}
$c -> DB -> disconnect ();
}
// 10. Render template and output
$tpl = $c -> View -> rendering ( $page );
exit ( $tpl ?? 0 );
The bootstrap process follows a clear lifecycle: Initialize → Configure → Route → Execute → Render → Output
Directory Structure
app/
├── bootstrap.php # Application entry point
├── config/ # Configuration files
│ ├── main.dist.php # Main configuration template
│ ├── install.php # Installation configuration
│ └── db/ # Database-specific configs
├── Controllers/ # Controller classes
│ ├── Primary.php # Primary controller
│ ├── Routing.php # Route definitions
│ ├── Install.php # Installation controller
│ └── Update.php # Update controller
├── Core/ # Core framework components
│ ├── Container.php # Dependency injection
│ ├── Router.php # URL routing
│ ├── View.php # Template engine
│ ├── DB.php # Database layer
│ ├── EventDispatcher.php
│ └── ...
├── Models/ # Data models
│ ├── Model.php # Base model class
│ ├── DataModel.php # Model with change tracking
│ ├── Page.php # Base page model
│ ├── User/ # User models
│ ├── Forum/ # Forum models
│ ├── Topic/ # Topic models
│ └── Post/ # Post models
├── templates/ # View templates
│ ├── _default/ # Default theme
│ └── _user/ # User-customizable theme
├── lang/ # Language files
├── cache/ # Cache directory
└── log/ # Log files
public/ # Web root
├── index.php # Web entry point
├── style/ # CSS and assets
└── img/ # Images
Request Lifecycle
Request Entry
Browser request hits public/index.php → includes app/bootstrap.php
Container Initialization
Load configuration → Create service container → Register services
Routing
Router matches URL to controller action → Extract parameters
Controller Execution
Controller receives request → Interacts with models → Returns Page object
Page Preparation
Page object sets template, title, breadcrumbs, navigation, etc.
View Rendering
View system compiles and renders template with page data
Response Output
HTTP headers sent → HTML output to browser
Design Patterns
Dependency Injection
All services are registered in the container and lazily instantiated:
// Services automatically receive the container
class MyService {
public function __construct ( protected Container $c ) {}
public function doSomething () {
$db = $this -> c -> DB ; // Lazy loading
$user = $this -> c -> user ; // Current user
}
}
Active Record Pattern
Models represent both data and behavior:
$user = $c -> users -> load ( 123 );
$user -> username = 'NewName' ;
$user -> email = '[email protected] ' ;
$c -> users -> update ( $user );
Event-Driven Architecture
Extensions can hook into application lifecycle:
$event = new Event ( 'topic:create:after' );
$event -> topic = $topic ;
$c -> dispatcher -> dispatch ( $event );
Services are only instantiated when first accessed, reducing memory usage and startup time.
View templates are compiled to PHP and cached. Cache is automatically invalidated when templates change.
Database Query Optimization
Uses PDO with prepared statements. Queries are optimized with proper indexing.
Full support for PHP opcode caching (OPcache). Automatically invalidates when code changes.
Configuration Architecture
Configuration is hierarchical and supports:
Environment-specific settings (development, production)
Service definitions (shared and multiple instances)
Parameter substitution using %param% syntax
Factory methods using @service:method syntax
Service Registration
Factory Methods
'shared' => [
'DB' => [
'class' => \ForkBB\Core\ DB :: class ,
'dsn' => '%DB_DSN%' ,
'username' => '%DB_USERNAME%' ,
'password' => '%DB_PASSWORD%' ,
'options' => '%DB_OPTIONS%' ,
'prefix' => '%DB_PREFIX%' ,
],
]
Next Steps
Routing System Learn how URLs are mapped to controllers
Models Understand the data layer
Controllers Create request handlers