Belin Framework Cookbook
Practical steps to install, configure, build, and ship apps with Belin. Start with a clean .env, wire up DB/Redis, learn the HTTP core, then use Craft to scaffold and ship.
1) Introduction & Installation
Install
composer create-project belinframework/framework my-project
cd my-project
php craft env:init # creates .env from .env.example
composer install # if needed
Project layout
public/index.php— front controllerconfig/*.php— core config;config/env/<env>/*.phpoverridessrc/Controller,src/Middleware,src/Core,src/Validationtests/— PHPUnitcraft— CLI entrypoint
2) Environment & Configuration
- Edit
.env(and optionally.env.<APP_ENV>) with:- App:
APP_ENV(development/production),APP_DEBUG,APP_MAX_REQUEST_BODY - Database:
DB_HOST/PORT/NAME/USER/PASSWORD - Queue:
QUEUE_DRIVER=sync|redis,REDIS_* - Storage:
STORAGE_ROOT - Security:
CORS_ALLOWED_ORIGINS,CSRF_*,SECURITY_*,TRUSTED_PROXIES
- App:
- Env-specific overrides live in
config/env/<APP_ENV>/*.phpand load after the base config. - Per-env files: if
APP_ENV=development,.env.developmentloads after.env. - Run the dev server:
php craft serve # http://localhost:8000 by default
php craft serve localhost:8080
3) Core HTTP Stack
Routing
Define routes in config/routes.php:
$router->get('/', [WelcomeController::class, 'index']);
$router->get('/api/status', [StatusController::class, 'index']);
$router->group(['prefix' => '/api', 'middleware' => [
// \App\Middleware\AuthHeaderMiddleware::class,
]], function (Router $r) {
$r->resource('/posts', \App\Controller\PostController::class); // RESTful routes
});
Optional controller fallback:
$router->enableControllerFallback(); // /user/profile -> UserController::profile()
Middleware
- Global middleware:
config/app.php(app.middleware). - Per-route middleware: third argument on routes or group middleware.
- Included:
SecurityHeadersMiddleware,CsrfMiddleware,RateLimitMiddleware. - Custom middleware implements
MiddlewareInterface::handle(Request $request, callable $next).
Requests & Responses
- Request (
App\Core\Request):input(),query(),json(),file(),has(),filled(),route('id'),ip(),isJson(),isSecure(),isAjax(),getRawBody(). - Validation:
$request->validate($rules)throwsValidationExceptionon failure. - Response (
App\Core\Response):success(),error(),created(),noContent(),notFound(),unauthorized(),forbidden(),validationError(),json(),redirect(),withHeader(),withCookie()(secure defaults).
Validation example
$data = $request->validate([
'email' => 'required|email',
'age' => 'integer|min_value:18',
'role' => 'in:admin,user,viewer',
]);
Rules: required, email, string, integer|int, float|numeric, boolean|bool, array, url, uuid, slug, min, max, between, min_value, max_value, in, regex. Messages/patterns: config/validation.php.
4) Data & Background Work
Storage helper
App\Core\Storage keeps file ops inside STORAGE_ROOT:
$storage = new Storage();
$path = $storage->path('uploads', 'file.txt');
$storage->write($path, 'hello');
$contents = $storage->read($path);
$storage->append($path, ' world');
Config: config/storage.php (root, subpaths, permissions).
JSON helper
App\Core\Json:
$data = Json::decode($json);
$email = Json::pointerGet($data, '/user/email');
Json::pointerSet($data, '/flags/active', true);
$merged = Json::mergePatch($data, $patch);
$encoded = Json::encode($merged, pretty: true);
Queues & jobs
- Configure driver in
.env:QUEUE_DRIVER=syncorQUEUE_DRIVER=rediswithREDIS_*. - Job shape:
use App\Queue\JobInterface;
use App\Core\Container;
class SendEmailJob implements JobInterface {
public function __construct(private array $payload = []) {}
public function handle(Container $container): void { /* send mail */ }
public function toArray(): array { return $this->payload; }
public static function fromArray(array $data): self { return new self($data); }
}
- Dispatch:
$queue = new \App\Queue\QueueManager();
$queue->push(new SendEmailJob(['to' => 'user@example.com']));
- Work:
php craft queue:work --sleep 500 # respects QUEUE_DRIVER
Events & legacy worker
queue:workerruns the Redis-backed event bus (App\Core\EventBus).- Prefer
queue:workfor new jobs; keepqueue:workerif you rely on the legacy event bus.
5) Security, Errors, Testing
- Error handling: JSON errors; stack traces only when
APP_DEBUG=true. - CORS/CSRF/Security: config-driven; defaults are locked down (
CORS_ALLOW_CREDENTIALS=false, limited origins unless set). - Trusted proxies: set
TRUSTED_PROXIES(comma-separated IPs) to honorX-Forwarded-For/Proto. - Request size: capped via
APP_MAX_REQUEST_BODY(413 when exceeded). - Testing:
vendor/bin/phpunit
Includes coverage for router, middleware, storage, JSON, validation, config env, and queue (sync).
6) Craft CLI Workflow
List all commands:
php craft list
High-velocity commands:
env:init [--force]— seed.envfrom example.- Make scaffolds:
make:controller <Name>,make:service <Name>,make:middleware <Name>,make:validation <Name>,make:error <Name>,make:core <Name>,make:entity|make:model <Name>,make:migration <Name>,make:event <Name>,make:listener <Name> [Event],make:crud <Name>,make:test <Name> [--unit|--integration]. - Routing helpers:
make:route <path> <Ctrl@method> [VERB]or--resource. - Runtime:
serve [host:port],queue:work [--sleep ms],queue:worker [--poll ms] [--batch n],tinker(REPL),delete <type> <name>.
7) Tips & Best Practices
- Keep
APP_DEBUG=falsein production. - Set precise
CORS_ALLOWED_ORIGINS; avoid*with credentials. - Prefer
QUEUE_DRIVER=redisand supervisequeue:workfor async tasks. - Use
config/env/<env>overrides instead of editing base configs. - Secure cookies/session when using cookie-based auth; prefer stateless tokens for APIs.