Skip to Content search facebook instagram pinterest twitter youtube

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.