Mini Framework - API Reference
Quick reference for Mini framework functions and classes.
Core Functions
Framework Bootstrap
bootstrap(): void # Initialize framework (error handlers, output buffering)
router(): void # Handle routing (calls bootstrap() internally)
Translation
t(string $text, array $vars = []): Translatable # Create translatable text
translator(): Translator # Get translator instance
HTML & Output
h(string $str): string # HTML escape
render(string $template, array $vars = []): string # Render template from _views/
Template Inheritance
Inside templates, $this provides helpers for layout inheritance:
$this->extend(string $layout) # Extend parent layout
$this->block(string $name, ?string $value = null) # Define block (dual-use)
$this->end() # End buffered block
$this->show(string $name, string $default = '') # Output block with default
Dual-Use $this->block() Syntax:
// Inline: set block to value directly
$this->block('title', 'My Page');
// Buffered: capture block content
$this->block('content'); ?>
<p>Content here</p>
<?php $this->end();
Example:
// Child template (child.php)
<?php $this->extend('layout.php'); ?>
<?php $this->block('title', 'My Page'); ?>
<?php $this->block('content'); ?><p>Page content</p><?php $this->end(); ?>
// Parent layout (layout.php)
<html><head><title><?php $this->show('title', 'Untitled'); ?></title></head>
<body><?php $this->show('content'); ?></body></html>
// Including sub-templates (partials)
<?= mini\render('_user-card.php', ['user' => $currentUser]) ?>
// Multi-level inheritance (3+ levels)
// base.php → layout.php → page.php
URL Generation
url(string $path = '', array $query = []): string # Generate URL
redirect(string $url, int $statusCode = 302): void # Redirect
current_url(): string # Get current URL
Session & Flash Messages
session(): bool # Safe session initialization
flash_set(string $type, string $message): void # Set flash message
flash_get(): array # Get and clear flash messages
Database
db(): DatabaseInterface # Get request-scoped database instance
DatabaseInterface Methods:
query(string $sql, array $params = []): array # All rows
queryOne(string $sql, array $params = []): ?array # First row or null
queryField(string $sql, array $params = []): mixed # First field of first row
queryColumn(string $sql, array $params = []): array # First column as array
exec(string $sql, array $params = []): bool|int # Execute (returns last insert ID or true)
lastInsertId(): ?string # Get last insert ID
tableExists(string $tableName): bool # Check if table exists
transaction(\Closure $task): mixed # Run closure in transaction
Tables (Query Builder)
table(string $name): Repository # Get table repository
Repository Methods:
eq(string $field, mixed $value): Repository # WHERE field = value
gte(string $field, mixed $value): Repository # WHERE field >= value
lte(string $field, mixed $value): Repository # WHERE field <= value
gt(string $field, mixed $value): Repository # WHERE field > value
lt(string $field, mixed $value): Repository # WHERE field < value
in(string $field, array $values): Repository # WHERE field IN (...)
like(string $field, string $pattern): Repository # WHERE field LIKE pattern
order(string $field, string $direction = 'asc'): Repository # ORDER BY
limit(int $limit): Repository # LIMIT
offset(int $offset): Repository # OFFSET
all(): array # Fetch all results
first(): ?object # Fetch first result
count(): int # Count results
page(int $page, int $perPage = 20): array # Paginated results
Cache
cache(?string $namespace = null): CacheInterface # Get cache instance
CacheInterface Methods (PSR-16):
get(string $key, mixed $default = null): mixed
set(string $key, mixed $value, null|int $ttl = null): bool
delete(string $key): bool
clear(): bool
has(string $key): bool
getMultiple(iterable $keys, mixed $default = null): iterable
setMultiple(iterable $values, null|int $ttl = null): bool
deleteMultiple(iterable $keys): bool
Logging
log(): LoggerInterface # Get PSR-3 logger instance
LoggerInterface Methods (PSR-3):
emergency(string $message, array $context = []): void
alert(string $message, array $context = []): void
critical(string $message, array $context = []): void
error(string $message, array $context = []): void
warning(string $message, array $context = []): void
notice(string $message, array $context = []): void
info(string $message, array $context = []): void
debug(string $message, array $context = []): void
Internationalization
fmt(): Fmt # Get formatter instance
Fmt Static Methods:
Fmt::currency(float $amount, string $currencyCode): string
Fmt::dateShort(\DateTimeInterface $date): string
Fmt::dateLong(\DateTimeInterface $date): string
Fmt::timeShort(\DateTimeInterface $time): string
Fmt::dateTimeShort(\DateTimeInterface $dt): string
Fmt::dateTimeLong(\DateTimeInterface $dt): string
Fmt::number(float|int $number, int $decimals = 0): string
Fmt::percent(float $ratio, int $decimals = 0): string
Fmt::fileSize(int $bytes): string
Authentication
setupAuth(\Closure $factory): void # Register auth implementation
auth(): ?AuthInterface # Get auth instance
is_logged_in(): bool # Check if user is authenticated
require_login(): void # Require authentication (throws 401)
require_role(string $role): void # Require specific role (throws 403)
AuthInterface (implement this):
interface AuthInterface {
public function isAuthenticated(): bool;
public function getUserId(): mixed;
public function hasRole(string $role): bool;
}
CSRF Protection
csrf(string $action, string $fieldName = '__nonce__'): CSRF # Create CSRF token
CSRF Class Methods:
$token = new CSRF('delete-post'); # Create token for action
$token = new CSRF('update-user', 'token'); # Custom field name
$token->getToken(): string # Get token string
$token->verify(?string $token, float $maxAge = 86400): bool # Verify token
$token->__toString(): string # Output hidden input field
Usage Example:
// Generate token
$nonce = csrf('delete-post');
echo render('form.php', ['nonce' => $nonce]);
// In template
<form method="post">
<?= $nonce ?>
<button>Delete</button>
</form>
// Verify token
$nonce = csrf('delete-post');
if ($nonce->verify($_POST['__nonce__'])) {
// Process form
}
Security Features:
- Tokens signed with HMAC-SHA256 using
Mini::$mini->salt - Salt auto-generated from machine fingerprint + persistent random (zero-config)
- Includes session ID and user agent for additional security
- Time-based expiration (default 24 hours, customizable)
- IP address validation
- Self-contained tokens (no server-side storage needed)
Core Classes
Translatable
class Translatable implements \Stringable {
public function getSourceText(): string
public function getVars(): array
public function getSourceFile(): ?string
public function __toString(): string # Returns translated text
}
Translator
class Translator {
public function setLanguageCode(string $languageCode): void
public function trySetLanguageCode(string $languageCode): bool
public function getLanguageCode(): string
}
Mini (Container)
class Mini implements ContainerInterface {
public static Mini $mini; # Global instance
public readonly string $root; # Project root
public readonly PathsRegistry $paths; # Path registries
public readonly bool $debug; # Debug mode
public readonly string $locale; # Default locale
public readonly string $timezone; # Default timezone
public readonly string $defaultLanguage; # Default language
public readonly string $salt; # Cryptographic salt (auto-generated or MINI_SALT)
public function addService(string $id, Lifetime $lifetime, Closure $factory): void
public function has(string $id): bool
public function get(string $id): mixed
public function loadConfig(string $filename, mixed $default = null): mixed
public function loadServiceConfig(string $className, mixed $default = null): mixed
}
Lifetime Enum
enum Lifetime {
case Singleton; # One instance per application
case Scoped; # One instance per request
case Transient; # New instance every time
}
HTTP Exceptions
throw new Http\NotFoundException($message); # 404
throw new Http\AccessDeniedException($message); # 401/403
throw new Http\BadRequestException($message); # 400
throw new Http\HttpException($code, $message); # Custom code
Routing
File-Based Routes
Files in _routes/ directory map to URLs:
_routes/index.php → /
_routes/users.php → /users
_routes/api/posts.php → /api/posts
Pattern Routes
In _config/routes.php:
return [
"/users/{id:\d+}" => fn($id) => "_routes/users/detail.php?id={$id}",
"/posts/{slug}" => fn($slug) => "_routes/posts/detail.php?slug={$slug}"
];
Directory Routes
In _routes/api/__DEFAULT__.php:
return [
"/api/users" => fn() => "_routes/api/users.php",
"/api/posts/{id}" => fn($id) => "_routes/api/posts/detail.php?id={$id}"
];
Configuration
Environment Variables
MINI_ROOT=/path/to/project # Project root
MINI_CONFIG_ROOT=/path/config # Config directory
MINI_ROUTES_ROOT=/path/routes # Routes directory
MINI_VIEWS_ROOT=/path/views # Views directory
MINI_LOCALE=nb_NO # Default locale
MINI_TIMEZONE=Europe/Oslo # Default timezone
MINI_LANG=nb # Default language
MINI_SALT=your-random-salt-here # Cryptographic salt (optional, auto-generated if not set)
DEBUG=1 # Debug mode
Config Files
All config files in _config/ directory:
bootstrap.php- Application initializationroutes.php- Pattern-based routesPDO.php- PDO factory overridePsr/Log/LoggerInterface.php- Logger overridePsr/SimpleCache/CacheInterface.php- Cache override
CLI Commands
composer exec mini serve # Start development server
composer exec mini serve --host 0.0.0.0 --port 3000 # Custom host/port
composer exec mini migrations # Run pending migrations
composer exec mini translations # Validate translations
composer exec mini translations add-missing # Add missing translation strings
composer exec mini translations add-language nb # Create new language
composer exec mini translations remove-orphans # Remove unused translations
composer exec mini benchmark # Run performance benchmarks
ICU MessageFormat Syntax
Plurals
t("{count, plural, =0{no items} =1{one item} other{# items}}", ['count' => 5])
Ordinals
t("{place, selectordinal, one{#st} two{#nd} few{#rd} other{#th}}", ['place' => 21])
Select
t("{gender, select, male{He} female{She} other{They}}", ['gender' => 'male'])
Date/Time/Number Formatting
t("Today is {date, date, full}", ['date' => new DateTime()])
t("Price: {amount, number, currency}", ['amount' => 19.99])
Testing Helpers
function test(string $description, callable $test): void {
try {
$test();
echo "✓ {$description}\n";
} catch (\Exception $e) {
echo "✗ {$description}\n";
echo " Error: {$e->getMessage()}\n";
}
}
function assertEqual($expected, $actual, string $message = ''): void {
if ($expected !== $actual) {
throw new \Exception($message ?: "Expected != Actual");
}
}
Native PHP Integrations
Mini uses native PHP directly where appropriate:
Request Data
$_GET['param'] # Query parameters
$_POST['field'] # Form data
$_FILES['upload'] # File uploads
$_SERVER['REQUEST_METHOD'] # HTTP method
$_SERVER['HTTP_*'] # Request headers
$_COOKIE['name'] # Cookies
Locale & Formatting
\Locale::setDefault('nb_NO') # Set locale
\Locale::getDefault() # Get locale
date_default_timezone_set('Europe/Oslo') # Set timezone
date_default_timezone_get() # Get timezone
Intl Classes
$formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::CURRENCY);
$formatter = new \IntlDateFormatter(\Locale::getDefault(), ...);
$formatter = new \MessageFormatter(\Locale::getDefault(), $pattern);
$collator = new \Collator(\Locale::getDefault());
Service Override Pattern
Override framework services using config files:
// _config/Psr/Log/LoggerInterface.php
return new \Monolog\Logger('app', [
new \Monolog\Handler\StreamHandler('php://stderr'),
]);
// _config/PDO.php
return new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
// _config/mini/UUID/FactoryInterface.php
return new \mini\UUID\UUID4Factory(); // Use v4 instead of v7
See PATTERNS.md for detailed examples.
APCu Functions
Mini provides automatic APCu polyfills when the native extension is unavailable. All standard APCu functions work regardless of whether APCu is installed.
Basic Operations
apcu_store(string $key, mixed $value, int $ttl = 0): bool
apcu_fetch(string $key, bool &$success = null): mixed
apcu_exists(string|array $keys): bool|array
apcu_delete(string|array $key): bool|array
apcu_clear_cache(): bool
Atomic Operations
apcu_entry(string $key, callable $generator, int $ttl = 0): mixed # Fetch-or-compute
apcu_add(string $key, mixed $value, int $ttl = 0): bool # Store if not exists
apcu_cas(string $key, int $old, int $new): bool # Compare-and-swap
apcu_inc(string $key, int $step = 1, bool &$success = null, int $ttl = 0): int|false
apcu_dec(string $key, int $step = 1, bool &$success = null, int $ttl = 0): int|false
Information
apcu_cache_info(bool $limited = false): array|false # Cache statistics
apcu_sma_info(bool $limited = false): array|false # Shared memory info
apcu_key_info(string $key): ?array # Key metadata
apcu_enabled(): bool # Check availability
Usage Examples
// Simple caching
apcu_store('config', $config, ttl: 300);
$config = apcu_fetch('config', $found);
// Fetch-or-compute pattern (atomic)
$data = apcu_entry('expensive:calculation', function() {
return performExpensiveCalculation();
}, ttl: 60);
// Atomic counter
apcu_inc('page:views', 1);
$views = apcu_fetch('page:views');
// Conditional update
if (apcu_cas('counter', 5, 10)) {
echo "Updated counter from 5 to 10";
}
Driver Selection
When native APCu is not installed, Mini automatically selects the best available driver:
- Swoole\Table - Coroutine-safe shared memory (requires Swoole)
- SQLite - Persistent storage in
/dev/shm(requires pdo_sqlite) - Array - Process-scoped fallback (no persistence)
Configuration (optional):
# .env
MINI_APCU_SQLITE_PATH=/custom/path.sqlite # Custom SQLite path
MINI_APCU_SWOOLE_SIZE=4096 # Swoole table size
MINI_APCU_SWOOLE_VALUE_SIZE=4096 # Max value size
See README.md (APCu Polyfill section) for complete documentation.
Performance Tips
- Use APCu for L1 caching - Sub-millisecond operations via
apcu_entry() - Use direct SQL for simple queries - Skip the query builder when not needed
- Cache expensive operations - Use
cache()for computed results - Lazy initialization - Services only load when used
- File-based routing - No route compilation needed
- Request-scoped caching - Database, cache, logger instances reused within request
Common Patterns
Form Handling
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$email = $_POST['email'] ?? '';
// Validate, save, redirect
db()->exec('INSERT INTO users (username, email) VALUES (?, ?)', [$username, $email]);
redirect(url('users'));
}
echo render('form.php', ['title' => t('Create User')]);
API Endpoints
header('Content-Type: application/json');
try {
$users = db()->query('SELECT * FROM users')->fetchAll();
echo json_encode($users);
} catch (\Exception $e) {
log()->error('Failed to fetch users', ['exception' => $e]);
http_response_code(500);
echo json_encode(['error' => 'Internal server error']);
}
Protected Routes
require_login();
require_role('admin');
$users = db()->query('SELECT * FROM users')->fetchAll();
echo render('templates/admin/users.php', ['users' => $users]);
See Also
- README.md - Getting started and philosophy
- PATTERNS.md - Advanced patterns (service overrides, middleware, response processing)
- CLAUDE.md - Development guide for Claude Code