Scorpio has a rich view system for the MVC component. This allows different template engines to be used (on a per site basis) depending on the requirements and complexity of the project. Typically views are used to render a representation of the model state based on the request and are read only. Several utility classes are available to help ensure that the view remains read-only (this will be touched on later).
Out of the box Scorpio has support for the following template engines:
You are free to use any others - providing that they have an appropriate adaptor created that maps the mvcViewEngineBase to the template engine. The mapping does not have to be perfect or completely feature rich (see the examples above).
If no template engine is specified, then Smarty is used. Smarty and the generic PHP engine are bundled with Scorpio but the others will require downloading and setting up manually.
Template engines can be specified in the site specific config.xml file by adding a "templateEngine" property to the "site" section. This is per-site and is not inherited. Care should be taken to stick to a single template engine if creating inheritable sites. Most of the template systems have specific syntax and are not compatible.
Regardless of the engine used, some features are universally available to all engines whether they themselves have that capability or not. These features include:
- Template Resolution
- Controller View includes
Template resolution in Scorpio is quite a bit different to other systems. There are several steps involved, the first is content negotiation. Based on the request the appropriate output type is selected. This pre-configures the mime-type header and the template suffix that is used for rendering. If no user intervention is made, then Scorpio will attempt to render the result using the interpreted path.
For example: a request is made to the home page from a web browser. The request is interpreted as a HTML request and Scorpio attempts to render the results via the home.html.tpl file (in Scorpio all template files are .TYPE.tpl - this is not optional and is required). To switch output on the fly simply append /as.TYPE - so long as a template exists to render the result. Scorpio supports html, xhtml (for mobiles), wml, xml, json, js, atom, rss and fragment as output types. Fragment is a special case for returning small chunks of HTML instead of full page renders e.g. in AJAX requests.
Certain types are auto-set based on the URI. If the domain starts wap. or xml. or rss. then XHTML (or WML), XML or RSS output will be rendered automatically. When dealing with mobile content, Scorpio can auto-detect if XHTML or WML should be served.
The second step is resolving the actual template to use. In Scorpio sites are hierarchical i.e. they inherit. This is built-in and offers an extremely powerful and flexible system for creating web applications that can be custom tailored from a base application. In the view system this means that templates can be overridden on a per site basis just by creating the appropriate path and file in the site.
Because of this feature, it is critical that when including other template files the Scorpio methods are used instead of the template engines standard include methods.
When including other templates you do not need to specify an extension. It is all handled automatically for you. For example: in a HTML page you want to include the shared "menu" template: you simply use your template engines include method and then pass as the argument: $oView->getTemplateFile('menu', 'shared').
Scorpios view helper system is similar to Zend Frameworks: you create helper classes that will render various bits or perform some repeated action. You can register any number of namespaces where the helpers can be located from. A namespace is just a prefix for your helper classes e.g. MyProjectViewHelper or mvcViewHelper (the default).
View helpers are invoked by calling the method directly on the mvcViewBase object in the template and are mapped through the PHP __call magic method. For example: you add a view helper "MyProjectViewHelperCoolMenu" and map the namespace, you would then call the helper by using: $oView->coolMenu() in your template. Why $oView? Scorpio always assigns the current view object to the template as $oView - unless you change it (which you can).
View resources implement the __toString magic method so can be used as a string where they output the contents as formatted HTML. toString() is also available, note that if you use the output wrapper you cannot just echo a string, you will need to call __toString or toString directly.
Protecting Models and Data
Views should always be read-only - they should never be able to change the model state. To help enforce this Scorpio has an output wrapper. This is an optional utility class that allows objects to be wrapped with an access layer that blocks access to methods and properties. By default it only allows access to get, has, is, toString, __toString, allow, count and if an array or iterator: Foreach, getArrayCount, getArrayValue, arrayKeyExists and IteratorAggregate.
There is also an additional getSeed which returns the original seed object and a getSeedClassName.
The output wrapper can be configured at object wrapping time with other custom methods that you wish to permit access to e.g. buildPathUri from the controller class (mapped in mvcViewBase).
The output wrapper can be applied to any variable type in PHP except resources, however it will only function on objects and arrays (not much to do on a string or number!). Any sub-objects or methods that return arrays or more objects will be automatically wrapped.
An additional feature is if you use the wrapped object as a string the permitted method list will be echo'd out so you can see which methods you are allowed to call.
Finally: the output wrapper system is not compatible with some template systems (notably Twig). When using Twig as a template engine, any wrapped object has the wrapping stripped otherwise Twig will raise errors or just fail.
Important note: the output wrapper does NOT escape variables. It is an access control layer only. You will still need to escape (or use automatic escaping) in your view engine.