For AI Assistants: This page provides structured reference data optimized for rapid context acquisition. Use this as your primary reference when working with BoomStick projects.
Project Overview
Framework Identity
Framework: BoomStick PHP MVC
Purpose: Lean framework for AI-assisted rapid development
Architecture: Module-based MVC (Model-View-Controller)
PHP Version: 8.x+
Namespace: BoomStick\
Key Directories:
/lib/ Core framework libraries
/module/ Application modules (entry points + feature modules)
/bin/ CLI scripts (module generators, etc.)
/docker-config/ Docker service configurations
/template/ Module templates for generator
Entry Point Pattern:
/module/entry-[name]/ Web-accessible entry point module
Public root: /module/entry-[name]/public/
Index file: /module/entry-[name]/public/index.php
File Naming Conventions
CONTROLLERS:
Location: module/[name]/controller/
Pattern: [ControllerName].ctlr.php
Class: BoomStick\Module\[ModuleName]\Controller\[ControllerName]
Extends: BoomStick\Lib\Controller
ROUTES:
Location: module/[name]/route/
Pattern: [RouteName].route.php
Class: BoomStick\Module\[ModuleName]\Route\[RouteName]
Extends: BoomStick\Lib\Route
VIEWS:
Location: module/[name]/render/view/
Pattern: [view-name].view.php
Usage: $this->bodyView = 'view-name';
LAYOUTS:
Location: module/[name]/render/layout/
Pattern: [layout-name].layout.php
Usage: $this->setLayout('layout-name');
ELEMENTS (Partials):
Location: module/[name]/render/element/
Pattern: [element-name].element.php
Usage: $this->insertElement('element-name');
STYLES (Inline CSS):
Location: module/[name]/render/style/
Pattern: [style-name].style.php
Usage: $this->insertStyle('style-name');
SCRIPTS (Inline JS):
Location: module/[name]/render/script/
Pattern: [script-name].script.php
Usage: $this->insertScript('script-name');
LIBRARIES:
Core: lib/[ClassName].class.php
Module: module/[name]/lib/[ClassName].class.php
Namespace: BoomStick\Lib\ or BoomStick\Module\[ModuleName]\Lib\
Module Structure
module/entry-[name]/
├── controller/
│ └── [Name].ctlr.php # Controller class
├── lib/
│ └── [Name].class.php # Module-specific libraries
├── public/
│ ├── index.php # Entry point (DO NOT MODIFY structure)
│ ├── css/
│ │ ├── default.css # Module styles
│ │ └── vendor/ # Vendor CSS (Bootstrap, etc.)
│ ├── js/
│ │ └── vendor/ # Vendor JS (jQuery, Bootstrap, etc.)
│ └── images/ # Static images
├── render/
│ ├── element/
│ │ └── [name].element.php # Reusable partials
│ ├── layout/
│ │ └── default.layout.php # Page wrapper layout
│ ├── script/
│ │ └── [name].script.php # Inline JavaScript
│ ├── style/
│ │ └── [name].style.php # Inline CSS
│ └── view/
│ └── [name].view.php # Page content views
└── route/
└── [Name].route.php # URL routing definitions
MVC Request Flow
REQUEST LIFECYCLE:
1. REQUEST
└─▶ public/index.php (entry point)
├── Loads autoloader
├── Initializes Globals (G::$request, G::$session, G::$route)
└── Includes route files
2. ROUTING
└─▶ route/[Name].route.php
├── $route->register('Controller/action', '/url-path')
├── Matches URL pattern to controller/action
└── Extracts URL parameters (%i = int, %s = string)
3. CONTROLLER
└─▶ controller/[Name].ctlr.php
├── Action method executes
├── Sets view variables: $this->varName = $value
├── Sets view: $this->bodyView = 'view-name'
└── Calls $this->render()
4. RENDERING
└─▶ render/layout/default.layout.php
├── Wraps content in HTML structure
├── Calls $this->insertElement('head')
├── Outputs $bodyContent (the view)
└── Calls $this->insertScript('name')
5. VIEW
└─▶ render/view/[name].view.php
├── Access controller vars: $varName or $this->varName
├── Insert elements: $this->insertElement('name')
├── Insert styles: $this->insertStyle('name')
└── Output HTML content
6. RESPONSE
└─▶ HTML sent to browser
Common Tasks (Copy-Paste Ready)
Add a New Route
// In: module/[name]/route/[Name].route.php
// Basic route
$route->register('ControllerName/actionName', '/url-path');
// Route with integer parameter
$route->register('ControllerName/show', '/items/%i');
// Route with string parameter
$route->register('ControllerName/category', '/category/%s');
// Named route (for reverse routing)
$route->register('ControllerName/action', '/path')->name('route-name');
// POST-only route
$route->register('ControllerName/save', '/api/save')->POST();
// GET-only route
$route->register('ControllerName/list', '/api/list')->GET();
Add a Controller Action
// In: module/[name]/controller/[Name].ctlr.php
public function actionName()
{
// Set page metadata
$this->currentPage = 'page-identifier';
$this->pageTitle = 'Page Title';
$this->pageDescription = 'Meta description for SEO.';
$this->pagePath = '/url-path';
// Pass data to view
$this->someVariable = 'value';
$this->items = $this->fetchItems();
// Set which view to render
$this->bodyView = 'view-name';
// Render the output
$this->render();
}
Create a View
// In: module/[name]/render/view/[name].view.php
<?=$this->insertStyle('style-name');?>
<?=$this->insertElement('nav');?>
<main class="container my-5">
<h1><?=$pageTitle;?></h1>
<?php foreach($items as $item): ?>
<div><?=$item['name'];?></div>
<?php endforeach; ?>
</main>
<?=$this->insertScript('script-name');?>
Access Request Data
use BoomStick\Lib\Globals as G;
// GET/POST parameters
$id = G::$request->id;
$name = G::$request->name;
// Check request method
if (G::$request->isPOST()) {
$data = G::$request->getPOST();
}
// JSON payload (AJAX)
if (G::$request->isAJAX()) {
$json = G::$request->getJSON();
}
// URL parameters (from route patterns)
$params = G::$route->getParameters();
$itemId = $params[0]; // First %i or %s value
Session Management
use BoomStick\Lib\Globals as G;
// Set session data
G::$session->userId = 123;
G::$session->isLoggedIn = true;
// Get session data
$userId = G::$session->userId;
// Check if exists
if (isset(G::$session->isLoggedIn)) { }
// CSRF token for forms
$token = G::$session->CSRFToken();
Core Classes Quick Reference
// GLOBALS (BoomStick\Lib\Globals as G)
G::$debug; // bool - Debug mode
G::$route; // Route instance
G::$request; // Request instance
G::$session; // Session instance
G::$version; // Framework version
// CONTROLLER (BoomStick\Lib\Controller)
$this->bodyView = 'name'; // Set view file
$this->setLayout('name'); // Set layout (default: 'default')
$this->render(); // Output to browser
$this->renderReturn(); // Return as string
$this->insertElement('name'); // Include element partial
$this->insertView('name'); // Include another view
$this->insertStyle('name'); // Include style file
$this->insertScript('name'); // Include script file
$this->insertRoute('name', [params]); // Get URL for named route
// ROUTE (BoomStick\Lib\Route)
$route->register('Ctrl/action', '/path'); // Register route
$route->register(...)->name('name'); // Named route
$route->register(...)->POST(); // POST only
$route->register(...)->GET(); // GET only
G::$route->getParameters(); // Get URL params array
G::$route->byName('name', [params]); // Reverse route lookup
// REQUEST (BoomStick\Lib\Request)
G::$request->propertyName; // Get GET/POST param
G::$request->isPOST(); // bool
G::$request->isGET(); // bool
G::$request->isAJAX(); // bool
G::$request->getPOST(); // array of POST data
G::$request->getJSON(); // decoded JSON body
G::$request->getRequestedPath(); // Current URL path
G::$request->getMethod(); // HTTP method string
// SESSION (BoomStick\Lib\Session)
G::$session->key = 'value'; // Set
$val = G::$session->key; // Get
isset(G::$session->key); // Check
G::$session->all(); // Get all as array
G::$session->CSRFToken(); // Get CSRF token
G::$session->URLToken(); // Get URL-safe token
// DEBUG (BoomStick\Lib\Debug as D)
D::printr($var); // Print and continue
D::printre($var); // Print and exit
D::console($var); // Send to console listener
D::timer('id'); // Start/stop timer
CLI Tools
# Set module name variable (replace "bang" with your module name)
export module="bang"
# Module Generator
./bin/make-module --help # Show help
./bin/make-module -m $module # Create entry module
./bin/make-module -t nodejs --entry-point-module=$module -m $module # Create nodejs module
./bin/make-module -t composer --entry-point-module=$module -m $module # Create composer module
# Entry Module Initialization (creates NginX config)
cd module/entry-$module && ./entry-init.sh && cd ../../
# Common options
--entry-point-module=[name] # Link to entry module (for nodejs/composer)
# Docker
docker compose up --build # Build and start dev environment
docker compose down # Stop containers
docker compose logs -f # Follow logs
# NPM (from nodejs module directory)
cd ./module/nodejs-$module/
npm install # Install dependencies
npm run all # Build all vendor assets
# Composer initialization
cd ./module/composer-$module && ./init-entry.sh # Install autoloader into entry module
Quick Setup One-Liner
Set your module name and run this single command:
export module="bang" && git clone https://github.com/cedarcoasters/boomstick.git BoomStick-$module && cd BoomStick-$module && ./bin/make-module -m $module && cd module/entry-$module && ./entry-init.sh && cd ../../ && ./bin/make-module -t nodejs --entry-point-module=$module -m $module && cd ./module/nodejs-$module/ && npm install && npm run all && cd ../../ && ./bin/make-module -t composer --entry-point-module=$module -m $module && cd ./module/composer-$module && ./init-entry.sh && cd ../../ && docker compose up --build
Code Patterns
Complete Page Implementation Pattern
// 1. ROUTE: module/[name]/route/[Name].route.php
$route->register('MyController/myPage', '/my-page');
// 2. CONTROLLER: module/[name]/controller/[Name].ctlr.php
public function myPage()
{
$this->currentPage = 'my-page';
$this->pageTitle = 'My Page Title';
$this->pageDescription = 'Description for meta tags.';
$this->pagePath = '/my-page';
// Fetch/prepare data
$this->items = $this->getItems();
$this->bodyView = 'my-page';
$this->render();
}
// 3. VIEW: module/[name]/render/view/my-page.view.php
<?=$this->insertStyle('index');?>
<?=$this->insertElement('nav');?>
<header class="page-header text-white py-5">
<div class="container">
<h1><?=$pageTitle;?></h1>
</div>
</header>
<main class="container my-5">
<?php foreach($items as $item): ?>
<div class="card mb-3">
<div class="card-body">
<h5><?=$item['title'];?></h5>
<p><?=$item['content'];?></p>
</div>
</div>
<?php endforeach; ?>
</main>
<?=$this->insertScript('index');?>
// 4. NAV: Add to module/[name]/render/element/nav.element.php
<li class="nav-item">
<a class="nav-link <?=$currentPage === 'my-page' ? 'active' : '';?>" href="/my-page">
<span class="material-icons align-middle me-1">icon_name</span> My Page
</a>
</li>
JSON API Response Pattern
// Controller action for API endpoint
public function apiEndpoint()
{
header('Content-Type: application/json');
if (!G::$request->isAJAX() && !G::$request->isPOST()) {
echo json_encode(['error' => 'Invalid request']);
return;
}
$data = G::$request->getJSON();
// Process request...
$result = ['status' => 'success', 'data' => $processedData];
echo json_encode($result);
}
Form Handling Pattern
// Controller
public function formPage()
{
if (G::$request->isPOST()) {
// Validate CSRF
if (G::$request->csrf_token !== G::$session->CSRFToken()) {
$this->error = 'Invalid CSRF token';
} else {
// Process form
$name = G::$request->name;
$email = G::$request->email;
// Save data...
$this->success = 'Form submitted successfully';
}
}
$this->bodyView = 'form-page';
$this->render();
}
// View
<form method="POST">
<input type="hidden" name="csrf_token" value="<?=G::$session->CSRFToken();?>">
<input type="text" name="name" required>
<input type="email" name="email" required>
<button type="submit">Submit</button>
</form>