Upgrading
The breaking changes between releases, and what to do about each one when you update.
On this page
Update the framework with Composer, then work down this page from the version you are on. Run phlat registry:check and phlat health:check when you are done. Every change is also listed in Updates.
v0.20.0
Hx::navigate() is Hx::redirect(). Rename each call.
Prefs is Options. Use $app->options in place of $app->prefs, rename the prefs config key to options, and point a page with view @phlat/prefs at @phlat/options. Visitor cookies are now option_{key}, so saved choices reset once.
GitResult is ProcResult. Rename each type hint and use statement.
code.theme is fieldtype.code.theme. Move the key in site/config.json.
Icons are an addon. {icon()} now comes from the icons addon. Run phlat addons:mount icons to create its page, and keep that page published and hidden: it serves the sprite. Move any icon you added to phlat/icons/ into site/views/@icons/.
v0.19.0
FieldType is stateless. One instance is shared per class and each method receives the FieldValue: encode(FieldValue $field, mixed $raw), decode(FieldValue $field), validate(FieldValue $field, mixed $raw), empty(FieldValue $field), preview(FieldValue $field), indexValues(FieldValue $field), indexChildren(FieldValue $field) and indexText(FieldValue $field). FieldType::create() is removed; a type is built as new $class($app). __get() is child(FieldValue $field, string $key). A custom field type overrides the new signatures.
Field render templates moved beside the definition. site/views/fields/{name}.latte is site/fields/{name}/render.latte, and site/views/fields/{type}.latte is site/fieldtypes/{type}/render.latte (site/fieldtypes/@phlat/{type}/render.latte to override a core type). site/views/fields/{view}/{name}.latte still takes precedence. Move each file to its new name.
v0.18.0
find() returns one type. A query that names no type= returns pages only, where it used to match user rows too. Add type=user to a query meant to return users. Any other type= value throws.
The image pipeline is $app->pageFiles()->image. generateVariant() is image->generate(), resolveOptions() and resolveLayers() are on the same object, and PageFiles::parseOptions() is Image::parseOptions().
Removed methods. Order with sort= in the query instead of RecordCollection::sort(). Use $app->users() in place of User::root(), parent(), children() and url(). Use History::commitIfDirty($page) or batch($message, $fn) in place of History::commit(). The template functions cacheKey, cacheOf and cachePut are gone; {cache} needs no change.
v0.17.2
App::bind(), make() and trigger() are removed. An addon creates its own objects in index.php. Use Hx::trigger() to set HX-Trigger. Page::slug(), Page::folder() and Registry::all() are also removed.
v0.17.1
The session cookie is sent only over HTTPS. php.ini sets session.cookie_secure=1. A site served over plain HTTP, such as local development, cannot keep a session until it uses HTTPS or turns the setting off. Sites on their own php.ini should copy the new lines from phlat/php.ini.
v0.17.0
{companion} is {component}. Replace {companion with {component and {/companion} with {/component} in your templates.
v0.16.0
A write clears the caches of its page and the pages above it, not the whole fragment cache. A fragment or {cache} region that lists pages outside its own page's subtree now stays until its TTL runs out. Add in: '/', or the path of a page above everything it lists, so a write below that page clears it. The cache tables are rebuilt on first use, so nothing needs clearing.
{cache} with a key: needs in:. A region shared between pages compiles only when it names the page that holds it:
{cache 'nav', 300, key: $section->uuid, in: '/'}
v0.15.0
Sessions are written through Ses only. A session is read once per request and released at once, so $_SESSION is a snapshot. A direct $_SESSION['key'] = ... is never saved. Use Ses::set(), $page->session() or $app->session->scope($name). Ses::isActive() is now true only while a write holds the lock, so a check for "has this request read the session" uses Ses::isStarted(). Remove any Ses::close() you added to free the lock before a slow call: it is no longer held.
Signed-out visitors hold the guest role. can() and requirePermission() check the built-in guest role for them, and it grants nothing. It used to grant pages.view, which nothing read. To give visitors a permission, add site/roles/guest/_index.json with it. See Users and roles.
The assets, favicon and fonts pages are editor views. /assets, /favicon and /fonts need admin.access. Their files still serve publicly. A site that linked visitors to one of the overview pages needs its own view.
v0.14.0
Code fields render their own <pre>. The code field highlights with Phiki, and {$page->field}, |render and {highlight()} return a complete <pre> element with the theme's background. A template that wraps the value in <pre><code> now nests two. Drop the wrapper and style a container:
<div class="rounded-box overflow-hidden *:p-4 *:overflow-x-auto">{$value|noescape}</div>
Code that used Tempest\Highlight directly no longer autoloads; use {highlight($code, $lang)} or Phiki\Phiki.
v0.13.0
Pages moved to site/pages/, a git repository of their own. Content was in site/data/pages/. History commits and Sync pushes to the new repository, and site/data/ holds only state. The app refuses to boot until site/data/pages/ is moved. Code that built paths as "{$app->data}/pages/..." uses "{$app->pages}/...". Update deploy.php, compose files and backups, and on a deployed server move shared/site/data/pages to shared/site/pages before the next deploy.
A leading _ marks system files. Rename in every page, user and definition folder:
| Before | After |
|---|---|
index.json |
_index.json |
data.json |
_data.json |
data.autosave.json |
_draft.json |
{name}.index.json |
_{name}.json |
This covers views/, fields/, fieldtypes/ and roles/ too. A managed file whose own name starts with _ must be renamed. Then run phlat registry:rebuild.
Image variants are named with ~. photo.card.jpg is now photo~card.jpg. Delete site/data/storage/registry.db*, run phlat registry:rebuild and phlat files:rebuild, and replace any hard-coded variant URL with $image->src('card').
v0.12.0
data:migrate and collection:migrate are removed. A project still on a layout from before v0.10 gets no warning. Apply the v0.10.0 and v0.9.0 entries below by hand.
isThrottled() is removed. $app->session->throttle($key, $max, $window) records an attempt and returns whether the limit is passed.
v0.11.0
Mutating requests are checked by origin. The CSRF token is gone: a POST, PUT, PATCH or DELETE from another origin gets a 403. Remove token inputs from forms.
@ui components take one item shape. Lists take title, description, href and icon, and buttons take title, color and variant. A template passing label or class to a hero button renders it empty.
Every collection item needs a page. create() throws for an empty parent, reversing the item with no page added in v0.10.0. phlat registry:check lists items with no page, and --heal moves them to the home page.
v0.10.0
site/data/storage/ is split. History's deploy key moved to site/data/git/, and caches to site/data/cache/. storage/ keeps the registry, locks and rate limits. Move storage/git to git/, then delete storage/cache and storage/files.
Collection databases moved. site/data/pages/_{field}/items.db is now site/data/collections/{field}.db. Move each file with its -wal and -shm files.
v0.9.0
Collection items live only in their database. Items used to be folders under their page. Moving them needs each item to go through Collection::create(), so back up first with phlat backup:create.