Verified against Semitexa Ultimate 2026.10.03.1952

Settings Pages

A settings page is one class. Its fields say what can be set, and each field's default is the value until someone saves another:

#[AsSettingsPage(
    id: 'playground.store',               // where the values are stored, and the route name
    path: '/playground/settings/store',
    title: 'Store',
    group: 'playground.store',            // the settings area this page is a section of
    description: 'How the shop presents itself, and when stock counts as low.',
    permission: 'settings.manage',
    nav: 'Account',
    layout: '@project-layouts-Playground/layouts/app.html.twig',
)]
final class StoreSettings extends SettingsDefinition
{
    public function fields(): array
    {
        return [
            Field::text('storeName')->required()->set('max', 80)->default('Semitexa Shop'),
            Field::choice('currency', ['EUR' => 'Euro', 'USD' => 'US dollar'])->required()->default('EUR'),
            Field::integer('lowStockThreshold')->required()->set('min', 0)->default(5),
            Field::boolean('maintenance')->default(false),
        ];
    }
}

Read a value where you need it:

$threshold = $this->settings->of(StoreSettings::class)['lowStockThreshold'];   // SettingsValues

What the class gives you

The page a protected route rendered on @platform-ui/pages/settings, with one form
Sections every page of the same group is a section of one settings area, ordered by order, each listed only for a visitor who may open it
Saving the settings.save form action, with the page signed into the form; the field rules run on the server, then check(), then each field is stored
Storage semitexa/platform-settings, one setting per field under the page's id, for the request's tenant
Reading SettingsValues::of(): what was saved, else the field's default
Navigation and Ctrl+K nav: lists the page through crud_nav(), and the palette finds it by its title

A page with a permission requires it, both to see the page and to save it. Without one, any signed-in visitor may do both. Values that are per visitor (a profile, a preference) are not settings pages: store them per user.

Rules across fields

public function check(array $values): array
{
    return $values['lowStockAlert'] === true && $values['alertEmail'] === null
        ? ['alertEmail' => 'Say where the alert should go.']
        : [];
}

The answer shows on the field, and nothing is saved.

When a change is seen

The worker that saved sees the change at once. Other workers keep a snapshot of a module's settings for up to two seconds (SettingsModuleSnapshots::TTL_SECONDS), so they see it within that time.

The Playground's Store and Notifications pages (/playground/settings/store) are one settings area. The dashboard's Low stock widget reads the threshold from it.

Have a product idea?One free MVP every month