Controllers

Controllers inject data into a view at render time. They return an array merged into the template's variables.

What controllers do

A controller is a PHP file that runs just before a view renders. It receives $app, $page, and the context merged so far, and returns an array of variables merged into the template data. Use controllers to fetch related pages, prepare navigation lists, or compute display data that every page of a given view needs.

Controllers are view-scoped only, the right place for data that belongs to an entire view type, not for data tied to a specific route or request.

Naming and location

Controllers are colocated with their view's templates and router, inside site/views/:

site/views/{view}/controller.php
phlat/views/{view}/controller.php   ← framework-shipped views (e.g. admin)

A page with view blog loads site/views/blog/controller.php, if one exists, controllers are optional.

Controller structure

Return a callable that accepts App, Page, and the merged $context from prior layers, and returns an array:

<?php

use Phlat\App;
use Phlat\Page;

return function (App $app, Page $page, array $context): array {
    $posts = $app->page('blog')
        ->children('status=published, sort=-created');

    return compact('posts');
};

The returned keys become template variables:

{foreach $posts as $post}
    <a href="{$post->url()}">{$post->title}</a>
{/foreach}

Controllers that always run

Page::render() merges exactly two layers, in order:

  1. The global controller, views/controller.php, looked up via the special view name app, runs for every page regardless of view
  2. The page's own view controller (if one exists)

The view controller receives the global controller's return value as $context, and its own return values take precedence on key collision. There's no automatic parent-view or ancestor-page merging beyond these two layers, a controller that wants another view's data fetches it explicitly with $page->controller('otherView', $context).

The global controller

Phlat ships no default views/controller.php, it's entirely up to the site. This project's own site/views/controller.php provides the variables its layout templates need: $page, $assets, $logo, $logo_icon, $nav, $scripts, $styles, built from a couple of file/image lookups and $app->config->get('nav', []). A different site is free to return a different set of variables from its own global controller.

Scope

Controllers run only during page rendering, never in route handlers, auth guards, or any other execution context. If you need data inside a route handler, retrieve it directly in the handler closure.

<?php
// site/views/articles/controller.php

use Phlat\App;
use Phlat\Page;

return function (App $app, Page $page, array $context): array {
    $articles = $app->page('articles')
        ->children('status=published, sort=-created');

    return compact('articles');
};