Overrides
How site templates, routers, and controllers take priority over addon and framework defaults, and how to compose instead of copy.
The chain
A view's template, router and controller are each resolved by name across a fixed chain of roots. For an addon view such as @admin/login:
site/views/@admin/login/index.latte ← checked first
phlat/addons/admin/views/login/index.latte ← addon default
router.php and controller.php use the same chain. For a plain site view the chain is site/views/{view}/... then phlat/views/{view}/.... The first file that exists wins.
An override replaces, it doesn't merge
If site/views/@admin/login/index.latte exists, it fully replaces the addon's template. None of the addon's markup runs unless the override references it. The same holds for router.php (none of the addon's routes register) and controller.php (none of its data is returned).
A naive override therefore starts as a copy of the whole file, which drifts from the addon's original as it evolves. Compose instead of copying.
Templates
A template can't extend itself. {layout '@admin/login/index.latte'} inside site/views/@admin/login/index.latte resolves back to the override, because site/views/ is checked first. Override at a seam instead: when an addon template pulls in pieces with {include}, place a file of the same name under site/views/@admin/ and the rest keeps running.
When building an addon, or a site view meant to be overridden, split it into small partials at the points a caller is likely to customize.
Controllers
An override controller can include the addon's original by path and layer data on top. Page::controller() would resolve back to the override, so include the file directly:
<?php
// site/views/@admin/login/controller.php
return function (Phlat\App $app, Phlat\Page $page, array $context): array {
$original = (include "{$app->system}/addons/admin/views/login/controller.php")($app, $page, $context);
return [...$original, 'showSupportLink' => true];
};
Routers
Include the addon's router to register its routes first, then add or replace routes on the same $page->router:
<?php
// site/views/@admin/login/router.php
return function (Phlat\App $app, Phlat\Page $page): void {
(include "{$app->system}/addons/admin/views/login/router.php")($app, $page);
$page->router->get('sso', fn() => ...);
};
Full overrides
Replace the whole thing when the change is large: a login page redesigned from scratch, or a router with a different route set. Compose when customizing a seam.