API Reference

Auto-gegenereerd via Reflection — blijft altijd in sync met src/.

Filter: alleAppCacheCmsDbDebugDynamicEventsFilesFormHtmlHttpImageLogMediaSecuritySessionStdlibSupportView

Container

Framework\App\Container
final class

Minimale DI-container, PSR-11 compatible.

- `bind()` voor transient services (factory wordt elke get() opnieuw aangeroepen)
- `singleton()` voor services die maar één keer geconstrueerd worden
- `instance()` voor reeds gemaakte objecten

Geen auto-wiring: explicit is better than implicit voor een klein framework.

Gooit:
- {@see NotFoundException} (PSR-11 NotFoundExceptionInterface) als id onbekend is
- {@see ContainerException} (PSR-11 ContainerExceptionInterface) als factory faalt

6 public methods
bind(string $id, Closure|string $factory): void
get(string $id): ?mixed
has(string $id): bool
instance(string $id, ?mixed $instance): void
make(string $id): object

Typed resolver — return-type matcht de meegegeven class-string.
Gooit ContainerException als de service van het verkeerde type is.

singleton(string $id, Closure|string $factory): void

ContainerException

Framework\App\ContainerException
class

Generieke container-fout (factory crash, dubbele binding, etc.).
Voor "service niet gevonden" → {@see NotFoundException}.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

EnvLoader

Framework\App\EnvLoader
final class

Minimale .env-parser — geen Composer-dependency nodig.

Ondersteund formaat:
DB_HOST=127.0.0.1
DB_NAME="mijn_db" # aanhalingstekens worden gestript
DB_PASS='geheim'
# dit is een commentaarregel
LEGE_WAARDE=

Laadt waarden in $_ENV en $_SERVER, en via putenv().
Bestaande waarden (bijv. gezet door de webserver/Docker) worden
NIET overschreven — de omgeving wint altijd.

Gebruik:
EnvLoader::load('/pad/naar/.env');
$host = EnvLoader::get('DB_HOST', '127.0.0.1');

3 public methods
static get(string $key, ?string $default = NULL): ?string

Lees een omgevingsvariabele — zoekt in $_ENV, $_SERVER en getenv().
Geeft $default terug als de variabele niet bestaat.

static isLoaded(): bool

Geeft true als EnvLoader::load() al is aangeroepen.

static load(string $path): void

Laad een .env-bestand. Idempotent: tweede aanroep met hetzelfde
bestand heeft geen effect.

Kernel

Framework\App\Kernel
final class

Kernel — framework-kernel, CMS-vrij.

Eén instance per request. Kern-services hangen als readonly virtual properties
(PHP 8.4 property hooks) zodat ze kort opvraagbaar zijn maar nog steeds via
de container resolven — testen kan via Kernel::swap() of $kernel->container.

$kernel->router->get('/path', $handler);
$kernel->router->post('/path', $handler);
$kernel->layout->wrap(...)
$kernel->get(SomeService::class)

8 public methods
bind(string $id, Closure|string $factory, bool $singleton = true): void
static boot(string $appRoot, bool $debug = false, bool $registerErrorHandler = true): self

Boot een Kernel met de standaard kern-services geregistreerd.
CMS-bootstrap (Website, etc.) gebeurt daarna door de aanroeper.

static current(): self
get(string $id): ?mixed
handle(\ServerRequest $request): \Response

Verwerk het verzoek en geef de gerenderde {@see Response} terug. Pure
functie (geen `header()`/`echo`-side-effects) — testbaar via PHPUnit.

Trailing-slash redirects, dispatch, 404 en 405 worden hier afgehandeld.

instance(string $id, ?mixed $value): void
run(): void

Verwerk het huidige HTTP-verzoek en stuur de response (status, headers,
body) naar de client. Wrappert {@see handle()} met de IO-laag.

static swap(?self $kernel): void

Swap voor tests. Geef null om te resetten.

Layout

Framework\App\Layout
final class

Paginawrapper met sidebar-layout.

Sidebar-data staat in `config/sidebar.php` zodat de structuur op één plek
beheerd wordt en de live-search dezelfde lijst kan gebruiken.

__construct(string $appRoot)
2 public methods
notFound(string $requestedPath = ''): string

Render een 404-pagina, gewikkeld in de standaard layout.

wrap(string $title, string $content): string

Wikkel content in de volledige HTML-pagina.

NotFoundException

Framework\App\NotFoundException
final class

Gegooid door {@see Container::get()} als de gevraagde id niet geregistreerd is.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)

Route

Framework\App\Route
final class

Eén geregistreerde route. Bevat:
- methods : welke HTTP-methods matchen (lege list = alle)
- pattern : regex-pattern voor `$request->url->path`
- action : callable(ServerRequest): string|\Stringable
- middleware: per-route stack (na de globale Router-middleware)

`$route->middleware()` is chainable — lift-en-shift maakt 'm mutable maar
de constructor-properties blijven readonly.

__construct(array $methods, string $pattern, ?mixed $action)
3 public methods
getMiddleware(): array
matchesMethod(string $method): bool

Is `$method` toegestaan voor deze route? Lege methods-list = altijd ja.

middleware(callable ...$middleware = ?): self

Voeg één of meer middleware-callables toe. Een middleware krijgt
`(ServerRequest $req, callable $next)` en moet `$next($req)` aanroepen
(of een eigen response teruggeven om de chain te short-circuiten).

RouteResult

Framework\App\RouteResult
final class

Resultaat van `Router::dispatch()`.

Drie outcomes:
- **Matched** → URL én HTTP-method matchen; `response` draagt status,
headers en body
- **Method not allowed** → URL matched, method niet; `allowedMethods` lijst
gaat in de `Allow:`-header van een 405-response
- **Not found** → geen URL match; consumer rendert een 404

Pure value-object; geen state, alleen tagging.

6 public methods
isMatched(): bool
isMethodNotAllowed(): bool
isNotFound(): bool
static matched(\Response $response): self
static methodNotAllowed(array $allowed): self
static notFound(): self

Router

Framework\App\Router
final class

Router — regex-based, method-aware, met middleware-pipe.

Method-shortcuts:

$router->get ('/users', $handler);
$router->post ('/users', $handler);
$router->put ('/users/(\d+)',$handler);
$router->patch ('/users/(\d+)',$handler);
$router->delete('/users/(\d+)',$handler);
$router->any ('/healthz', $handler); // alle methods
$router->match (['GET','POST'],'/contact', $handler); // custom set

Capture-groups in het pattern komen door als positionele route-params:

$router->get('/articles/([a-z0-9-]+)',
fn(ServerRequest $req) => 'Slug: ' . $req->param(0));

Middleware (PSR-15-stijl, maar simpler):

$router->use(fn($req, $next) => $next($req)); // globaal
$router->get('/admin', $h)->middleware($authMw); // per-route

Een middleware krijgt `(ServerRequest, callable $next)` en MOET `$next($req)`
aanroepen om door te gaan, of een eigen response (`Response`/string/\Stringable)
returnen om te short-circuiten (bv. een redirect of 401).

`dispatch()` returnt een {@see RouteResult} met drie outcomes: matched,
methodNotAllowed (405), notFound (404).

9 public methods
any(string $pattern, callable $action): \Route

Match alle HTTP-methods op dit pattern.

delete(string $pattern, callable $action): \Route
dispatch(\ServerRequest $request): \RouteResult
get(string $pattern, callable $action): \Route
match(array $methods, string $pattern, callable $action): \Route

Match een expliciete set methods.

patch(string $pattern, callable $action): \Route
post(string $pattern, callable $action): \Route
put(string $pattern, callable $action): \Route
use(callable $middleware): self

Registreer globale middleware (loopt vóór de per-route middleware).