Application architecture
- Home
- Application architecture
The top-level of the source code (within the src
directory) contains the main index.php
script which loads the rest of the system.
The system is comprised of the core cms, one or more modules (which provide custom features), and one or more skin templates, which provide the look-and-feel of the front end sites.
Top-level directories
There are a few top-level directories:
- config - the base config files for the system
- files - the storage area for the media repository
- media - common css and javascript files
- modules - first-party and third-party modules
- skin - front-end templates
- sprout - the core framework and CMS
These directories are detailed below.
The config directory
This is where the configuration files are stored. Different aspects of the system will be split into their own config files. Modules may also provide their own configuration file(s) in which case the example/default version of these files will be stored with the module, and the file should be copied into the top-level config directory prior to modification.
The files directory
This is where uploaded files - pdfs, images, docs, etc - are physically stored. This directory needs to be writable by the web server user.
The media directory
There are various common javascript and css files used by the cms, and they're stored in this directory, such as the javascript for the various form fields.
The modules directory
All first-party and third-party modules are stored in this directory. The base install comes with a few modules, such as the Demo
module and the Welcome
module.
The base install also incldues the HomePage
module. It's exepected that developers may customise this module to suit the specific needs of the website.
Each module has a distinct namespace within the SproutModules
namespace. The namespace should also contain the organisation name. The demo module has a namespace of SproutModules\Karmabunny\Demo
.
The skin directory
Website template skins are stored in this directory. There is one sub-directory for each skin which is available. When using subsites (a feature where a single cms powers multiple sites) then the different subsites will can use a distinct skin.
The special directory unavailable contains templates which can be loaded (via a config file) to temporarily disable a website, e.g. for maintenance.
The sprout directory
The core of the system is contained within the sprout directory - this includes both the base framework, the CMS components, and the admin area.
Config
There are multiple configuration files for different features.
Configuration is loaded using the Kohana::config
method, which takes a single argument of the config value to load. The nibbles in the config variable name are separated by periods, with the first nibble referencing the file name and subsequent nibbles representing keys of increasing depth in the $config
array structure.
// loads $config['site_title'] from sprout.php config file $value = Kohana::config('sprout.site_title');
Configuration files are merged together based on their load order, with the default config files in sprout/config
and modules/*/config
directory being loaded first, the top-level config files in the config
directory being loaded next, and the per-skin config files (for the currently loaded skin) in skin/*/config
loaded last.
Routes
Routes provide a mapping between incoming urls and controllers. They're defined in config file named routes.php
as an array, where the key is a regular expression and the value is the controller, method, and optionally method arguments. Regex replacements for arguments (e.g. $1
) can be used. The segments (controller, method, arguments) are all separated by slashes.
modules/Blog/config/routes.php
// Calls BlogController::list $config['blog/list'] = 'SproutModules\Blogs\Controllers\BlogController/list'; // Calls BlogController::view with two arguments, the post id and the output type $config['blog/view/([0-9]+)/json'] = 'SproutModules\Blogs\Controllers\BlogController/view/$1/json'; $config['blog/view/([0-9]+)'] = 'SproutModules\Blogs\Controllers\BlogController/view/$1/html';
The regexes for route selection are implied to be anchored to the start and end of the string.
The first matching regex will be used; subsequent routes will be ignored.
Controllers
Controllers provide the logic which handles the HTTP request - this may render HTML, generate JSON output, send an email, etc.
Controllers are located within a sub-namespace of the module called Controllers
and therefore within the Controllers directory.
modules/Blog/Controllers/BlogController.php
class BlogController extends Controller { public function view($post_id, $output_type) { // code to view a single post goes here } }
Controller methods can only be accessed if they're a public method, and all access must be via a route.
All admin-based controllers are located within the Controllers\Admin
namespace and must extend the ManagedAdminController
class. These controllers are registered for use in the admin, and then they can be accessed via various admin methods - list records, add a record, edit a record, etc. Details about registering admin controllers can be found on the page which describes admin controllers in depth.
Views
Views provide the rendering layer for the content. They're a PHP file located within the views
directory of the module, with a mechanism to pass data through from the calling code.
Calling code creates an instance of the View
class, and then can pass data by setting arbriatry values on the object. The view is then rendered using the render
method. The data gets exposed as variables within the view.
The argument to the view constructor is the name of the view, which contains the module name and also the filename of the view (minus the .php extension)
modules/Blog/Controllers/BlogController.php
$item_view = new View('modules/Blog/item'); $item_view->name = $post['name']; $item_view->text = $post['text'];
modules/Blog/views/item.php
<?php use Sprout\Helpers\Enc; ?> <h2><?php echo Enc::html($name); ?></h2> <p><?php echo Enc::html($text); ?></p>
This sample also makes use of the very useful Enc
helper, which has methods for encoding output into various formats.
Skins
Skins provide a page layout by which content views are rendered within.
Each skin is comprised of multiple files including home page template, inner page template(s), email templates, css files, javascript files, and images.
The framework does not impose any requirements to the data passed to the skin views, although the cms features (such as pages, search, etc) will pass specific values into the views.
Each site can have multiple skins, which may be used for multiple versions of the site (e.g. 'v1' and 'v2') or if a cms is powering multiple sites (e.g. 'mobile' and 'desktop' skins). Typical development would be to duplicate the default
skin into another directory, and then do the customisation work within that directory.
Calling code doesn't specify the skin name, only the template name. The skin name is auto-determined based on the settings of the current subsite.
modules/Blog/Controllers/BlogController.php
$skin = new View('skin/inner'); $skin->page_title = 'View blog post'; $skin->main_content = $item_view->render(); echo $skin->render();
In this example, $item_view
gets rendered and then wrapped into the inner.php
template of the currently-selected skin.
Helpers
Helpers expose common functions to controllers and views. Helpers are located within the Helpers namespace of the module.
The most common type of helper is a class which contains entirely static methods. Common examples include:
- Pdb - database access library with methods such as Pdb::query, Pdb::update, Pdb::insert, etc
- Enc - string encoding for output. Common in views. Methods include Enc::html, Enc::xml, Enc::url, etc
- Form - outputting of form fields, such as Form::text or Form::dropdown
- Validator - validation of HTTP request (get or post) data, such as the Validator::required method
There are also some helpers which are desiged to be instanced and used as objects, such as:
- View - for rendering front-ends
- Email - for sending emails
- Treenode - a node for a hierarchical tree structure
And some helpers have a class hierarchy, such as:
- LocaleInfo - LocaleInfoAUS, LocaleInfoFRA, LocaleInfoUSA, etc
- ColModifier - ColModifierBinary, ColModifierDate, ColModifierLookupArray, etc
In many cases the base class can be extended by third-party code in modules, such as defining a custom ColModifer
class.