This minimalist MVC framework added by composer helps you to create a complex, yet easy to maintain, web application by configuration ONLY:
- you configure routes for controller,
- add models for the app business functionality,
- optionally modify view templates.
The framework takes care of logs, database, multiple languages, user friendly HTTP errors, friendly URL.
- See https://github.com/WorkOfStan/seablast-dist/ for example of how to use it. It's a public template, so you can start creating your app by duplicating that repository.
- the default environment parameters are set in the conf/default.conf.php
- if Seablast Auth extension is present (i.e. referenced in composer.json), use also its configuration
- if Seablast I18n extension is present (i.e. referenced in composer.json), use also its configuration
- everything can be overriden in the web app's
conf/app.conf.phpor even in its local deploymentconf/app.conf.local.php - set the default phinx environment in the phinx configuration:
['environments']['default_environment']where the database credentials are stored. Then SeablastConfiguration provides access to MySQLi adapter through mysqli() method and PDO adapter through pdo() method. - the default
logdirectory (both for SeablastMysqli/SeablastPdo query.log and Debugger::log()) can be changed as follows->setString(SeablastConstant::SB_LOG_DIRECTORY, APP_DIR . '/log'). Anyway, only levels allowed bySeablastConstant::SB_LOGGING_LEVELare logged.
SeablastModel uses model field in APP_MAPPING to invoke the model in the App.
Model transforms input into knowledge, therefore the invoked class MUST have a public method knowledge() and expect SeablastConfiguration as a constructor argument.
- SeablastModel also expects Superglobals $superglobals argument (instead of injection like
$model->setSuperglobals($superglobals);if required by APP_MAPPING), so that the environment variables are always easily available. (Especially important for APIs.)
The minimal requirements can be implemented by SeablastModelInterface.
- If model replies with
restproperty, API response is triggered instead of HTML UI. If the default HTTP code should be changed, set it up in thehttpCodeproperty. - If model replies with
redirectionUrlproperty, then redirection is triggered (instead of HTML UI) with HTTP code 301. The HTTP code MAY be set to 301, 302 or 303 by thehttpCodeproperty. - If using the default BlueprintWeb.latte, the
titleproperty is displayed as the page title.
SeablastConstant::APP_MAPPING = route => [
'model' => '\App\Project\ResponseModel', // class name of the model,
'roleIds' => '1,2', // comma delimited roleIds permitted to access the route,
]- Feel free to use the default latte layout
{layout '../vendor/seablast/seablast/views/BlueprintWeb.latte'}which can be populated by your localnav.latteandfooter.latte.
- By default the route
/poseidondisplays the app administration. It is available only to the admin=1, editor=2 (their IDs are the same as used in Seablast Auth) with different rights. Note: admin can view/edit everything that editor can, so for admin you need to declare only what they can do on top of it.
This section describes how database tables and their columns are configured for viewing and editing in the admin interface, based on user roles.
The configuration is declarative and role-driven.
Admin table access is defined on three levels:
- Role → Accessible tables (plus permissions for DELETE_ROW or INSERT_ROW)
- Role → Table → Viewable columns
- Role → Table → Editable columns
Each level must be explicitly configured.
Before a table can be displayed or edited, it must be explicitly allowed for the given role.
->setArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_X,
['table1', 'table2']
)- Defines which tables are visible to a role
- If a table is not listed here, it will not appear at all, even if columns are defined later
->setArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_EDITOR,
['audios', 'translations']
)The EDITOR role can access the audios and translations tables.
Viewable columns are displayed in the admin table but cannot be edited.
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_X,
'table_name',
['column1', 'column2']
)- Defines which columns are shown in the table
- Columns listed here are read-only
- Columns must not be duplicated in the EDIT section
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_ADMIN,
'users',
['id', 'email', 'created', 'last_login']
)The admin can view these columns but cannot modify them.
Editable columns appear as form fields and can be modified.
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_EDIT . SeablastConstant::USER_ROLE_X,
'table_name',
['editable_column1', 'editable_column2']
)- Defines which columns can be edited
- Editable columns automatically appear in edit forms
- Columns must not appear in the VIEW section
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_EDIT . SeablastConstant::USER_ROLE_ADMIN,
'items',
['metadata_text', 'active', 'parent_id', 'order']
)The admin can modify these fields.
A column may appear only once.
A column must be defined in either:
VIEWorEDIT
Never in both.
- Prevents UI conflicts
- Avoids ambiguous form behavior
- Ensures clear permission boundaries
Before a user can insert or delete a row in a table, it must be explicitly allowed for the given role.
Be careful with the DELETE_ROW permission: deleting a category may trigger a cascading delete.
The INSERT_ROW permission only makes sense when the user also has the EDIT permission.
->setArrayString(
SeablastConstant::ADMIN_TABLE_DELETE_ROW . SeablastConstant::USER_ROLE_X,
['table1', 'table2']
)
->setArrayString(
SeablastConstant::ADMIN_TABLE_INSERT_ROW . SeablastConstant::USER_ROLE_X,
['table1', 'table2']
)| Level | Method | Purpose |
|---|---|---|
| Role → Tables | setArrayString() |
Which tables a role can access |
| Role → Tables | setArrayString() |
Which tables a role can insert rows into |
| Role → Tables | setArrayString() |
Which tables a role can delete rows from |
| Role → Table → VIEW | setArrayArrayString() |
Read-only columns |
| Role → Table → EDIT | setArrayArrayString() |
Editable columns |
// Step 1 – Allow table access
->setArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_EDITOR,
['new_table']
)
// Step 2 – Define viewable columns
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_VIEW . SeablastConstant::USER_ROLE_EDITOR,
'new_table',
['id', 'name']
)
// Step 3 – Define editable columns
->setArrayArrayString(
SeablastConstant::ADMIN_TABLE_EDIT . SeablastConstant::USER_ROLE_EDITOR,
'new_table',
['name', 'active']
)- Table access is role-based
- Columns are explicitly split into VIEW and EDIT
- A column may exist in only one section
- Tables must be registered before defining columns
This design guarantees predictable behavior, secure access control, and a clean admin UI.
Fields that use the color editor (instead of a textarea) also display the selected color as the background. This feature applies to all fields with the same name across all tables (field names MUST be unambiguous).
->setArrayString(SeablastConstant::ADMIN_COLOR_FIELDS, [
'color_main', // audios.color_main but also item.color_main which still makes sense
])- Roles are for access.
- Routes can be restricted to specific roles (allow-list only; no denies).
- Menu items can be both allowed and denied (e.g. don't show to an authenticated user).
- Groups are on top of it, e.g. for promotions, subscriptions etc.
- RBAC (Role-Based Access Control): SB_IDENTITY_MANAGER provided by application MUST have methods prescribed in IdentityManagerInterface, these populate FLAG_USER_IS_AUTHENTICATED and USER_ROLE_ID and also USER_ID.
All JSON calls and form submits MUST contain csrfToken handed over to the view layer in the $csrfToken string latte variable.
- PHP >=7.2 <8.6
- Latte
>=2.10.8 <4: For templating. - MySQL/MariaDB: For database backend.
- Tracy
^2.9.8 || ^2.10.9: For debugging. - Nette\SmartObject: A trait that helps enforce strict PHP behavior.
- jQuery 3.7.1: As a JavaScript framework.
- Universal Language Selector jQuery library: For language switching (used by Seablast I18n).
-
if flag
I18nConstant::FLAG_SHOW_LANGUAGE_SELECTORis active (default in Seablast\I18n), then CSS and JS dependencies are already part of the template BlueprintWeb.latte. -
.eslintignore and .prettierignore to ignore third-party libraries, so that super-linter doesn't fail with JAVASCRIPT_ES and so that prettier doesn't change them or super-linter fails with CSS_PRETTIER, JAVASCRIPT_PRETTIER, JSON_PRETTIER, MARKDOWN_PRETTIER
-
To make the SVG icon in
.uls-triggeradopt thefont-colorof the surrounding element, the following style was added intouls/images/language.svg:fill="currentColor". Alsouls/css/jquery.uls.csswas changed (changed:.uls-trigger, added:.uls-trigger iconand.uls-trigger .icon svg). -
based on https://github.com/wikimedia/jquery.uls Revision: 077c71408284f446b626b656ce206e6ed3af705c Date: 17.07.2025 14:25:10
-
css\jquery.uls.css
.uls-trigger { background: url(../images/language.svg) no-repeat left center; padding-left: 24px; }
... changed to ...
.uls-trigger { padding-left: 24px; } .uls-trigger .icon { vertical-align: middle; } .uls-trigger .icon svg { height: 1em; /* přizpůsobí velikost textu */ }
-
images\language.svg
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
... changed to ...
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 20 20">
-
-
See https://github.com/wikimedia/jquery.uls/compare/077c71408284f446b626b656ce206e6ed3af705c...master to compare the changes in the latest version
- the constant
APP_DIR= the directory of the current application (or the library, if deployed directly) - don't start the value of a constant for a configuration field in the app.conf.php with SB to prevent value collision
| Directory | Description |
|---|---|
| .github/ | Automations |
| assets/ | Web assets available for browser (such as shared scripts) |
| cache/ | Latte cache - this is just for development as production-wise, there will be cache/ directory in the root of the app |
| conf/ | Default configuration for a Seablast app and for PHPStan |
| log/ | Logs - this one is just for development; as production-wise, there will be log/ directory in the root of the app |
| src/ | Seablast classes |
| tests/ | PHPUnit tests |
| views/ | Latte templates to be inherited (note: {try}{include file} masks compilation errors by preferring seablast/views) |
The PHPUnit tests use the database configuration from ./conf/phinx.local.php, so the library require-dev Phinx, ensuring PHPUnit tests work on GitHub as well.
./blast.sh phpstan runs PHPStan to test the repository.
It can also be called ./vendor/seablast/seablast/blast.sh from a Seablast application as a management script for deployment and development. Run ./blast.sh -? to see all the options.