feat(view): add the Twig engine alongside Plates
Twig 3 is installed and wired, but nothing renders through it yet: no .twig
template ships, so every page is still served by Plates.
- Themes are described by an optional themes/<name>/theme.php: a parent to
inherit from, the Vite entry points and free-form settings. A theme without a
manifest inherits from the default one, so existing themes keep working.
ThemeChainResolver expands a theme into the chain templates and assets are
looked up along.
- TemplatePathRegistry registers the namespaces by convention — @theme, @admin
and one per installed module — so a module needs no Twig configuration at all.
A module with unusual layout can add paths with the johncms.template_paths tag.
- One environment serves the whole of HTTP, with autoescape on, and
strict_variables and auto_reload following DEBUG. The compiled templates live
in data/cache/twig/web, outside the document root.
- Extensions: the app global (facts about the page, the user and the token
resolved only if a template asks), the translation helpers, asset(),
asset_exists(), vite(), avatar(), the value formatters, and plates(), which
lets a Twig page pull in a partial that has not moved yet.
- AssetResolver looks up a file along the theme chain and, unlike the Plates
extension, does not take the page down when it is missing outside DEBUG.
- New commands twig:lint (also part of the verification gate) and twig:compile.
- i18n:scan now walks .twig templates too, through a second scanner working on
the Twig AST — without it the strings of a migrated template would drop out of
the .pot files.