Quince

From The Smartest Wiki
Jump to: navigation, search

Quince is the MVC web controller library used by Smartest.

What does Quince do?

Quince ties together several crucial elements in the structure of an application:

  • URL - the requested path, for example /users/list
  • Class - a group of methods that are executed one-at-a-time as actions, for example Users.class.php
  • Action - the specific method executed, for example Users::list()
  • Configuration
  • Request variables:
    • URL variables
    • GET variables (which override URL variables)
    • POST variables (which override GET variable)

Smartest additionally uses the module and action names to determine which template shown in order to display the user interface, for example: Applications/Users/Presentation/list.tpl

Basic API

The Quince module's classes containing actions must extend the QuinceBase class in order to gain the basic API:

Redirection:

$this->redirect('/example/url');
$this->redirect('@route');
=> Throws QuinceRedirectException object

(See QuinceRedirectException)

Forwarding:

$this->forward('module','action');
=> Throws QuinceForwardException object

(See QuinceForwardException)

Accessing data about the current request:

$this->getRequest();
=> Returns QuinceRequest

(see QuinceRequest)

How does Smartest implement Quince?

In Smartest, Quince modules are called 'applications' to reflect Smartest's OS-like architecture.

User-created applications (Quince modules) are stored in the Applications/ folder in the top level Smartest directory. Smartest system applications are stored in System/Applications/.

In Smartest, Quince's central configuration file is stored at Configuration/quince.yml.

Structure and request handling

Software using Quince is divided into modules. Each module is a folder/directory that can ideally be installed/introduced into your project by simply being placed in a designated location. These locations are defined in the main quince.yml file parsed by Quince. In Smartest these locations are Applications/ and System/Applications/.

Each module has a short name to identify in URLs and routing, and is essentially a folder surrounding a central class, whose public methods are the actions that can be called on that module. Every action thus has a bipartite name of the module short name, followed by the action name.

For example, an action called 'editUser' in a module with a short name of 'users' would thus have a full name of users:editUser.

Actions can be triggered by visiting the corresponding URL path, so when the URL /users/editUser is requested, Quince will load the class file of the 'users' module (let us call this Users.class.php), check for the 'Users' class and instantiate it if present, and if this is successful, check for and call the editUser() action. If that action is not available, either because it is a private or protected method, or because it does not exist, the module's default action is called. If the default action does not exist either, an exception is thrown.

Each module stores its basic information in a configuration file inside the module's directory. This file is in YAML format, is usually called quince.yml and looks like the following:

module:
  class: ContactForm
  shortname: contact
  identifier: com.example.ContactForm
  longname: Contact Form
  default_action: validateHomepageMessage

These first few directives are essential, and allow Quince to associate the class name, module short name, standard application identifier with each other, as well as specify a user-friendly label and a default action for when none is specified.

All Quince modules are given basic MVC functionality by extending the QuinceBase bas class. Smartest applications are still descendants of this class, but extend either SmartestSystemApplication or SmartestUserApplication depending on whether they are part of the Smartest backend or not, respectively.

Additional features of Quince 2.0

Routing

Routes are named actions that can be referred to by name, rather than by the action they call or the URL that triggers them (which can both consequently be changed more easily). Routes simply bind together a URL with an action in a named way, and allowing request parameters to be part of the URL.

An example of a route (called 'edit_user') might look like:

routes:
  edit_user:
    action: editUser
    url: /users/edit/:username

This route has a required URL parameter called 'username', and references to it must include the value of this parameter, but do not need to specify the action/method name or the URL.

Routes are usually prefixed with an '@' and can be referred to:

  • in redirects: $this->redirect('@edit_user?username=mjgw')
  • in links, using the url_for block: <a href="{url_for}@edit_user?username=mjgw{/url_for}">Edit user</a>.

Both of these examples will produce the URL /users/edit/mjgw, which when visited will call the editUser action/method of the Users module, with a request parameter called username that has a value of 'mjgw':

In any module class that correctly extends the Quince base class QuinceBase, this can be accessed as follows:

echo $this->getRequest()->getRequestParameter('username');
=> 'mjgw'

In Smartest, the SmartestBaseApplication class and its descendants have been given an easier API:

echo $this->getRequestParameter('username');
=> 'mjgw'

Thus routes can have URLs that break the standard /modulename/actionName pattern, providing almost unlimited freedom with URLs.

Namespaces

When one module needs responses to use different classes, different templates, or different formats, these can be assigned to namespaces that precede the URL.

For example, take the following quince.yml configuration:

module:
  class: SampleModuleClass

Say that when the routed url /test/url is called, it calls the action sampleAction on the module (and the sampleAction() method on class SampleModuleClass using the following:

routes:
  example:
    url: /test/url
    action: sampleAction

To use a different class when an 'ajax:' namespace is added to the URL, the full URL becoming /ajax:test/url, the following would be added to the quince.yml file in the module:

namespaces:
  ajax:
    class: AlternativeClassName

The controller will now look for a sampleAction() method in the AlternativeClassName class instead.

URL aliases

Forwarding

If an action is called but is not appropriate to the current task, it can 'forward' the user to the correct action without the need to trigger a new HTTP request. Quince simply throws an exception of type QuinceForwardException with the desired module and action name, which is caught and processed such that the requested module and action are loaded. Up to ten consecutive forwards can be issued without any further error, meaning infinite loops are impossible.

History of Quince

Although Quince predates Smartest, it was originally called PHP-Controller, and was developed by Eddie Tejeda. Quince's website is located at www.quincecontroller.org.

Version 2.0

This is an entirely new, PHP5 native rewrite that will back-port many of the OS-like features of Smartest. It is a free-standing controller library that is developed as a side project to Smartest, but which can be used for other applications.

Features include:

  • Extensive caching.
  • Namespaces
  • YAML-based configuration.
  • Internal action forwarding (One action calls another - this is useful in form validation).
  • Directories as modules - no central controller file. This allows for drag & drop installation.
  • Customizable metadata on modules, so that for instance Smartest applications can register themselves as needing to have their helpers and extended objects loaded without forcing Smartest-specific features onto the Quince core.
  • Exceptions & error handling.
  • More flexible URLS, including spaces and non-roman characters (0.1-0.9 freak out when these characters are included in the URL)

Version 0.8

This version was a ground-up rewrite by Marcus Gilroy-Ware, though it still used the same API, was PHP4 Compatible, used a central XML controller file, and was contained within a single class.

New features in this version were:

  • Basic caching
  • Multiple module directories
  • Logging

Versions <= 0.7

These versions used the original codebase developed by Eddie Tejeda.