Mojolicious-Plugin-Fondation
view release on metacpan or search on metacpan
# NAME
Mojolicious::Plugin::Fondation - Hierarchical plugin loader with configuration priority and resource sharing
# VERSION
version 0.03
# SYNOPSIS
# In your Mojolicious application (myapp.pl or startup)
plugin 'Fondation' => {
dependencies => [
{ 'Fondation::User' => { title => 'Custom User' } },
'Fondation::Authorization',
],
};
# In a plugin (e.g. lib/Mojolicious/Plugin/Fondation/User.pm)
package Mojolicious::Plugin::Fondation::User;
use Mojo::Base 'Mojolicious::Plugin', -signatures;
sub fondation_meta {
return {
dependencies => [],
defaults => {
title => 'User Management',
items_per_page => 20,
},
};
}
sub register ($self, $app, $conf) {
$app->routes->get('/users' => sub ($c) { $c->render(text => "Users!") });
return $self; # Important for finalyze actions
}
sub fondation_finalyze ($self, $app, $long_name) {
# Optional: code to run after all plugins are loaded
$self->log->debug("User plugin fully loaded");
}
1;
# DESCRIPTION
Fondation attempts to provide a foundation for building websites from
pre-built bricks. It is a plugin loader for Mojolicious that enables
hierarchical, recursive plugin loading with automatic configuration
merging, resource sharing (controllers, templates), and post-load actions.
It is designed for modular applications where multiple plugins contribute
routes, templates, and behavior, while avoiding duplicate loads and
respecting configuration priorities.
Key features:
- Recursive plugin loading via `dependencies`
- Configuration cascade: direct > app config > plugin defaults
- Automatic discovery and registration of `share/templates`
- Application-level `share/templates` have priority
- Extensible post-load actions (Templates, Controllers, custom)
- Deferred initialization via `fondation_finalyze`
- Contextual logging via `$self->log` (Mojo::Log context)
# LOADING ORDER
1. load_plugin_recursive
ââ Fondation -> dependencies recursively
2. run_post_load_actions
ââ For every plugin (load order), execute all actions
(Templates, Controllers, custom)
ââ App-level share/templates added with highest priority
3. run_finalyze
ââ For every plugin (load order), call fondation_finalyze()
# QUICK START
# myapp.pl
use Mojolicious::Lite;
plugin 'Fondation' => {
dependencies => [
'Fondation::User',
'Fondation::Authorization',
],
};
# Fondation loads Authorization, which depends on Role + Permission.
# Result: Role -> Permission -> Authorization -> User
# All share/templates and controllers are auto-discovered.
## With a config file
# myapp.conf
{
'Fondation' => {
dependencies => ['Fondation::User', 'Fondation::Authorization'],
},
'Fondation::User' => {
title => 'User Management',
},
}
# myapp.pl
plugin 'Config';
plugin 'Fondation'; # reads dependencies from config
# CONFIGURATION PRIORITIES
Each plugin receives a merged configuration built from three sources,
combined with [Hash::Merge](https://metacpan.org/pod/Hash%3A%3AMerge). The cascade priority is:
### 1. Direct configuration (passed in `dependencies` array)
plugin 'Fondation' => {
dependencies => [
{ 'Fondation::User' => { title => 'Direct override' } },
],
};
### 2. Application configuration file (e.g. myapp.conf)
{
'Fondation::User' => {
title => 'From config file',
}
}
### 3. Plugin defaults (returned by `fondation_meta`)
sub fondation_meta {
return {
defaults => { title => 'Default value' },
};
}
The merge rules are:
- Scalars -- overwrite. The highest-priority non-empty value wins.
- Hashes -- merged recursively. Keys present at multiple levels are resolved
by priority; keys present at only one level survive untouched.
- Arrays -- concatenated. All values from all levels are kept, ordered
by priority: direct elements first, then app config, then defaults.
Example: a plugin declares `allowed_roles => ['user']` in its defaults,
the app config adds `allowed_roles => ['editor']`, and a direct dependency
passes `allowed_roles => ['admin']`. The merged result is
`['admin', 'editor', 'user']` -- all three roles are available, with the
highest-priority one first.
The `dependencies` key is not special -- it follows the same array
concatenation rules. This means an app config can add extra dependencies
without repeating those already declared.
# RESOURCE DIRECTORIES (share/)
Fondation automatically handles shared resources from plugins:
- `share/templates` -> pushed to `$app-`renderer->paths>
- `share/public` -> pushed to `$app-`static->paths>
The application's own `share/templates` directory (if it exists) is added
with `unshift` and therefore has \*\*highest priority\*\* (application templates
override plugin templates).
# ACTIONS (POST-LOAD PROCESSING)
Actions are classes that run after \*\*all\*\* plugins are loaded, iterating
over each plugin in load order. They perform specific initialization tasks
such as registering templates or controllers. Actions are configurable via
the `actions` key in Fondation's configuration.
( run in 0.494 second using v1.01-cache-2.11-cpan-9581c071862 )