How it works

What happens between a request arriving and HTML going out, and which file each step reads.

On this page

The pieces

Piece Where it lives What it does
Page site/pages/{path}/ A folder: _index.json for structure, _data.json for content, plus its files
View site/views/{view}/ The template, router, controller and field list shared by every page that names it
Field site/fields/{name}/ A named value with a type, listed by the views that use it
Registry site/data/storage/registry.db A SQLite index of the pages, for queries and search
Addon phlat/addons/, site/addons/ Extra views, fields, routes and services, such as the admin

The files are the truth. The registry is rebuilt from them, and the admin edits them like any other writer.

A request, step by step

  1. Resolve the page. The URL is walked from its deepest segment upward until a page folder matches. /blog/hello/comments finds site/pages/blog/hello/ and leaves comments as the sub-path.
  2. Check access. The page and each ancestor must be published and open to the visitor. Otherwise the request ends here with a 404, a login redirect or a 403.
  3. Route. The global router, each ancestor's view router and the page's own view router load in that order. Only the page's own routes are matched against the sub-path. before() hooks registered by any of them run first. A view with no router renders the page on GET.
  4. Run controllers. The global controller site/views/controller.php, then the view's controller.php, return arrays that become template variables.
  5. Render. The view's index.latte renders with $page and the controller variables. A URL ending in :blockname renders only that block.

Events fire along the way, such as app.route:after once the page is routed and page.render:before around rendering, so an addon can observe each step. See Event Hooks.

The same request in files

For /blog/hello/ with view post:

site/pages/blog/hello/_index.json   ← resolved: uuid, view: post, published
site/views/router.php               ← global router, hooks only
site/views/blog/router.php          ← the parent's view router, hooks only
site/views/post/router.php          ← routes matched here (optional)
site/views/controller.php           ← global controller (optional)
site/views/post/controller.php      ← view controller (optional)
site/views/post/index.latte         ← rendered
site/pages/blog/hello/_data.json    ← read as $page->title, $page->body, ...

Writes

A save goes through Page::save(), whoever makes it: the admin, the CLI or your code. It writes the page's files, updates the registry, records an entry in History and fires page.update:after. Editing a file by hand skips all of that, so run phlat registry:check --heal afterwards.

Overrides

Any file a view, field or addon ships can be replaced by a file at the same path under site/. See Overrides.

Next

Pages covers the folder layout in detail.