Request Routing
Routing in Festi is typically handled by a system plugin. The Jimbo system plugin is commonly used for this purpose.
Routing via the Jimbo Plugin
All plugins involved in routing must be registered in the festi_plugins table.
If Jimbo is used as the system plugin, routing is managed through the following tables:
festi_url_areas– Defines Routing Areas in the system, such as default, backend, etc.festi_url_rules– Stores regular expressions that define routes and specify which plugin and method should handle matching requests.festi_url_rules2areas– Links routing rules to specific system zones.
Routing Areas (festi_url_areas)
Routing Areas act as abstractions that allow the system to handle different use cases. For example, if both the admin panel and the website have the same URL (/login/), routing must direct requests to the appropriate handlers. By default, Jimbo assigns the default area.
Routing Setup Cycle:
- Add a routing rule to
festi_url_rules. - Link the rule to an area in festi_url_rules2areas.
Routing via Install SQL (Recommended)
URL rules should be registered in install SQL files (festi_url_rules + festi_url_rules2areas), not via runtime code. This ensures routes are installed with the plugin and available across all environments. Provide install scripts for all supported databases: PostgreSQL, MySQL, and MSSQL.
-- install/pgsql.sql
INSERT INTO festi_url_rules (url, id_plugin, method)
VALUES ('~^/contact/$~', (SELECT id FROM festi_plugins WHERE plugin = 'ContactUs'), 'onDisplayDefault');
INSERT INTO festi_url_rules2areas (id_rule, id_area)
VALUES (currval('festi_url_rules_id_seq'), (SELECT id FROM festi_url_areas WHERE area = 'default'));
Routing via $GLOBALS (Legacy)
Note: This approach is considered legacy. Prefer install SQL for cross-project plugins.
Routing rules can also be defined using the $GLOBALS['urlRules'] array. The key should be a regular expression that matches the desired URL, and the value should be an array containing the plugin name and method:
$GLOBALS['urlRules'] = [
'~^/my/test/([0-9]+)/$~' => ['My', 'onDisplayDefault']
];
Routing via the Web Interface
You can manage routing rules via the DGS interface available at: /festi/festi_url_rules/Jimbo/
Caching Url Rules
Routing rules are read from the database on every request. A project can serve them from its own cache instead by registering a cache listener — see Cache Events. Nothing changes until you do: without a listener the rules are read exactly as before.
One entry is cached per routing area, under url_rules.<prefix>.<area> — for
example url_rules.festi_.backend. The area is part of the key because the same
URL routes differently in different areas.
Invalidation is yours
Editing rules through
/festi/festi_url_rules/Jimbo/, through install SQL or through a migration does not invalidate the cache. Deleting a plugin removes its rules by foreign key cascade with no PHP involved at all. A cached routing table keeps serving the old routes until it expires.Give
GROUP_URL_RULESa bounded lifetime, and purge it as part of every deploy.
To purge one area immediately, rebuild its key and drop it through your own backend — the framework has no remove event, because the listener owns the storage:
$systemPlugin = Core::getInstance()->getSystemPlugin();
assert($systemPlugin instanceof ApiPlugin);
$key = $systemPlugin->getUrlRulesCacheKey('backend');
$cacher->remove($key, CacheEvent::GROUP_URL_RULES);
To purge automatically when an administrator edits a rule in the web interface,
hang the invalidation off the DGS: listen for Core::EVENT_ON_CREATE_STORE,
check whether the created store works on festi_url_rules or
festi_url_rules2areas, and attach Store::EVENT_INSERT, Store::EVENT_UPDATE
and Store::EVENT_REMOVE listeners that purge the affected areas. This belongs
in your project or your cache package rather than in the framework.
Rule precedence among overlapping patterns is not currently deterministic —
getUrlRules()has noORDER BYand the first matching rule wins — so a cached ordering can differ from an uncached one.
Regular Expressions in Routing
If regular expressions include capture groups, the extracted values will be passed as parameters to the plugin method. For example, given the pattern:
~^/my/([a-z]+)/([0-9]+)/$~
Calling the URL:
/my/go/123/
Will invoke the plugin method with the extracted parameters:
class MyPlugin extends DisplayPlugin
{
public function onDisplayDefault(Response &$response, $type, $id)
{
// $type = 'go'
// $id = 123
}
}