smart_toy 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.

info Project Overview

description 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

folder 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\

account_tree 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

sync_alt 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

build 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();

code 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

terminal 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

pattern 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>