The framework
One of the most fundamental piece within the framework is the context container.
Lion framework is organized by contexts, where each context represents a concrete application. At the very high level, a context is just a space where instances collaborate together without interfering with other contexts. i.e., a context manages his own session and cache, avoiding conflicts with other contexts running at the same time.
A context is linked to a physical directory where application's classes and configuration files are contained in. Each context is bound to a single directory, being able to handle his own configuration and classes.
The first context that lion loads is the one representing the main application (also known as application context).
Getting the application context is really simple: there is a singleton instance representing it. The context also exposes some accessor to retrieve context contained instances such the session or the configuration.
i.e.
<?php
//get the application context:
//get the context configuration:
$configuration = $application_context->getConfiguration();
//get the context session:
$session = $application_context->getSession();
//get the context cache:
$cache = $application_context->getCache();
Dependency injection
One of the most interesting capability of the context container is the known as Dependency Injection (aka inversion of control or IoC), being today's latest development craze.
Software components (Clients) are often a part of a set of collaborating components which depend upon other components (Services) to successfully complete their intended purpose. In many scenarios, they need to know 'which' components to communicate with, 'where' to locate them, and 'how' to communicate with them. When the way such services can be accessed is changed, such changes can potentially require the source of lot of clients to be changed.
One way of structuring the code is to have the clients declare their dependency on services, and have some "external" piece of code assume the responsibility of locating and/or instantiating the services and simply supplying the relevant service references to the clients when needed. With this method, client code typically is not required to be changed when the way to locate an external dependency changes. This type of implementation is what's known as dependency injection.
In lion we can declare the dependencies in the context configuration file and let the framework work out the complexities of service instantiation, initialization, sequencing and supplies the service references to the clients as required. This way to declare dependencies is based on Spring XML-style.
<?xml version = "1.0" standalone="yes"?>
<configuration>
<context-instances>
<context-instance id="userDao" class="UserDao">
<property name="dataSource" ref="mysqlDataSource"/>
</context-instance>
<context-instance id="mysqlDataSource" class="DataSource">
<property name="dataEngine"><value>mysql</value></property>
<property name="host"><value>localhost</value></property>
<property name="user"><value>lion</value></property>
<property name="password"><value>rocks</value></property>
</context-instance>
</context-instances>
</configuration>
Each context container manages his own instances. In fact, the mechanism of locating object references is by calling to the appropriate context accessor:
<?php
//get the context instance userDao
The request dispatcher and the intercepting filter
Lion defines a complete infrastructure of modules and classes to dispatch and transform client requests in terms of application components.
The request dispatching mechanism receives many different types of requests, which require varied types of processing. Some requests are simply forwarded to a concrete controller, while other requests must be modified, audited, or uncompressed before being further processed.
When a request enters on Lion, it often must pass several entrance tests prior to the main processing stage. i.e. perform the user authentication, switch the language, validate certain constraints, ...
The key to solving this problem in a flexible and unobtrusive manner is to have a simple mechanism for adding and removing processing components, in which each component completes a specific filtering action. This pattern is known as intercepting filter, which is one of the most interesting features on Lion request dispatcher system.
The filters intercept incoming requests and outgoing responses, allowing preprocessing and post-processing. We are able to add and remove these filters unobtrusively, without requiring changes to our existing code.
<?php
/**
* Change the currency in session by a given one if the
* currency parameter is present within the request.
*
*/
public function preFilter(__IRequest &$request, __IResponse &$response) {
if($request->hasParameter('currency')) {
$currency_iso_code = $request->getParameter('currency');
//set the currency iso code within the CurrencyManager
//singleton instance:
CurrencyManager::getInstance()->
setCurrencyIsoCode($currency_iso_code);
}
}
}
Filters are executed before giving the control to the front controller (preFilter) and after returning the response to the client (postFilter).
Filters can be associated to routes declaratively within the configuration.
<?xml version = "1.0" standalone="yes"?>
<configuration>
<filters>
<filter name="myFilter" class="MyFilter">
<apply-to>
<route id="myRoute"/>
</apply-to>
</filter>
</filters>
</configuration>
The url rewrite engine
This is the Lion native URL rewrite engine, delegating the URL parsing from the webserver to Lion itself.
URL rewriting is a method of creating search engine friendly URLs, also known as SEO (Search Engine Optimization) URLs. Dynamic URLs have apparently a negative effect on search engine ranking. To get around this issue the URL rewriting technique is used. URL rewrite tools can examine a website and produce a simplified link for each resource on the website.
i.e. the link:
http://yourdomain.com/index.php?module=invoices&view_id=10948
can be changed to
http://yourdomain.com/invoices/10948.html
Different URL formats accepted by Lion are specified within route definitions. A route is a way to describe the mapping between an URL and how to route the execution flow.
A route defines a pattern for the URL, in pure perl compatible regular expression syntax. First found route matching an URL will be the one used to process the request.
A route defines the following components:
- Which front controller will attend the request.
- Which action/controller will be executed.
- Which other parameters will be appended to the request.
Because URL formats are sensible to be changed, Lion provides a class designed to cover the translation between url and route components in 2 directions: This class exposes methods to discompound an URL into components as well as to do the inverse task, to compose an URL as from the components.
The model-view-controller
Many frameworks follow the Model View Controller (MVC) architectural pattern to separate the data model, business rules and user interface.
Most MVC frameworks follow a push-based architecture. These frameworks use actions that do the required processing, and then "push" the data to the view layer to render the results.
An alternative to this is pull-based architecture, sometimes also called "component-based". These frameworks start with the view layer, which can then "pull" results from multiple controllers as needed. In this architecture, multiple controllers can be involved with a single view.
So, which MVC has lion?
Both of them: Lion integrates a push-based MVC really similar to spring's approach, but also implements a proprietary pull-based approach.
Both cooperate together in harmony during the execution life-cycle.
The component model
The lion component model may be one of the key pieces of the framework:
It reduces drastically the amount of code needed to bound UI component representation to server side instances, handling the following aspects:
- How component status are propagated between client and server
- How client events are sent synchronous or asynchronously to server.
- How events are dispatched on server
The way to handle an event is as simple as writing a single method to do that. No extra declarations to let lion know that a concrete event need to be handled by the server side. Changes are bound between client and server automagically.
In the other hand, by handling an event we are able to execute a world of operations such retrieve or update components status, access to the model, check security stuffs, manipulate the nagivation flow, ...
i.e., to shows the 'FoO BaR!' string on myLabel component once the user has click on the button myButton, a single method with just 2 lines of code:
<?php
/**
* Set the 'FoO BaR!' string to the myLabel text
* property when click the myButton component
*
*/
public function myButton_click() {
//retrieve the component myLabel
$my_label = $this->getComponent('myLabel');
//assign the 'FoO BaR!' to the text property
$my_label->setText('FoO BaR!');
}
}
We don't have to care about how to propagate the click event from client to server or how to call to this method once the event has been received on server side. Just 2 lines of code is enough.
Lion handles asynchronous calls to the server by using one of the most exciting technology: Ajax.
Ajax helped the Web to be faster by reducing the CPU load on the servers for tasks that are mostly cosmetic and have almost no interference in the application business logic.
When an event has raised, lion uses the Ajax call not just to send the event notification but client info that has changed since last time the component model was synchronized.
Custom components
In fact, component is more like a synonym of reusability: We don't want to develop again and again the same calendar widget.
Lion has been designed to make pretty easy the creation of new components, as this is a really common practice on application development.
It has a clear separation between the component logic and the UI rendering, allowing several representations over the same components for several client types.
There are some pieces within Lion destined to ease the binding between component's properties and client representation:
Lion understand the end-point concept associated to terminal pieces envolved on client-server synchronization. A client end-point is the piece on the client side, i.e. a javascript object property. Analog to the server end-point, i.e. a component property.
Lion exposes an API to establish bindings between client and server end-points. i.e. to bind the value property of a textbox component to the HTML input value representing it.
<?php
/**
* bind a given component's property (value) with an HTML
* element property.
*
*/
//server end-point:
//client end-point:
}
...
The security layer
Lion security layer is a RBAC designed to solve most of the authentication and authorization related tasks.
The RBAC, which means Role Based Access Control, is an access control pattern which defines one of the most flexible ways to administer access permissions.
This pattern defines a world of permissions and roles where we can protect some pieces of our web application, known formally as system resources. Each system resource has an associed permission, more like a lock requiring a concrete key. Each user has a set of roles. A role allow to access to a system resource if the required permission is covered by the role. i.e., an user with the role READ_POSTS could read posts on a forum while an user with the role WRITE_POSTS could create new posts but at the same time read existing posts.
Thanks to the dependency injection configuration facility, we can easily define the security layer by declaring involved instances and dependency between them.
<?xml version = "1.0" standalone="yes"?>
<configuration>
<context-instances>
<instance id="authenticationManager" class="__AuthenticationManager">
<property name="authenticators">
<list>
<ref id="authenticator"/>
</list>
</property>
</instance>
<instance id="authenticator" class="__Authenticator">
<property name="userLoader">
<ref id="userLoader"/>
</property>
</instance>
<instance id="userLoader" class="__UserLoader"/>
</context-instances>
</configuration>
The configuration and section handlers
Based on .net framework, the premise for the Lion configuration system is simple: to provide developers with a consistent manner for storing and reading configuration information.
The Lion configuration system features an extensible infrastructure opened for extension, providing the following benefits:
- Configuration information is allowed to be stored in several formats (XML, .ini files, ...) as well as several sources (files, database, ...). In that sense, Lion offers a flexible way to organize the configuration within an application.
- Configuration information is cached once it has been parsed and transformed. So there are not performance penalties in that sense.
- Lion configuration system is extensible. You can define new configuration parameters and write configuration section handlers to process them.
The Lion Configuration System provides several classes for programmatic access to the configuration settings. One of the key features within the configuration system is the capability to intercept a request for getting a concrete configuration section and execute a filter to transform the section in terms of application components.
By ussing section handlers we get 2 main benefits: to parse configuration fragments on demand and to uncouple configuration parsing classes from configuration consumers.
The class loader
I'm really bored about writing include directives on my PHP files, do you?
For that reason, one of the first features that was added to Lion framework was the class loader, a class in charge of include every php file just when needed.
Lion redirects the __autoload callback to the class loader, making possible to include any missing class files on demand. In the other hand, the class loader knows where is located every class by reading from some xml files, known as includepath files.
In an includepath file We can declare where is located a concrete class, but we can also specify a naming convention for a set of classes by ussing a pattern, easing the maintenance. Imagine that sometime a class can be loaded by just following what naming convention we have defined.
<?xml version = "1.0" standalone="yes"?>
<classes>
<!-- Controllers -->
<cluster name="Controllers" path="/libs/controllers">
<class name="*" file="*.class.php"/>
</cluster>
<!-- Model classes -->
<cluster name="Model" path="/libs/model">
<class name="*" file="*.class.php"/>
</cluster>
<!-- Event Handlers -->
<cluster name="Event Handlers" path="/libs/eventhandlers">
<class name="*" file="*.class.php"/>
</cluster>
</classes>
There are 3 main benefits on using the class loader:
- To avoid the use of include directives within php files. On small project this doesn't matter, but on relative big projects it becomes a great advantage.
- As consequence of the previous point, refactoring the code by moving files from one to other folder is a really easy task because just implies to adapt the specific includepath files without altering the code at all.
- To plug new libraries ready to use on lion by just adding new includepath files. Again, code does not need to know where libraries are located on.
What else?
Well, the purpose of this document is just to highlight some of the most important functionalities implemented on Lion.
However, apart from that, there are a bunch of rich features available on Lion:
- The model proxy, a way to publish model access services by uncouple where services are really located. Also usefull to publish some services as webservices.
- The action dispatcher, where front-controllers delegate on. This is also usefull to execute actions programatically.
- The exception handler, a way to organize error codes in groups and associate exception classes to each group declarativelly. Each error code can be also associated to a internationalized message.
- The I18n module, a way to provide the application with I18n capabilities. Language strings can be loaded from different sources (files, database, ...).
- Command line support, a way to execute lion applications from the command line by ussing PHP-CLI. Also a way to execute lion administrative commands. Requests are routed to an special front-controller designed to route to the most appropriate controller based on command-line parameters.
- The configuration stream wrapper, making transparent where a configuration file is retrieved from. i.e. the file config://servers.xml could be a physical file in a concrete location or the result of a query to an external database.
- The bootstrap capability, a way to create empty projects ready to use with Lion from the scratch by just writing one single line of code.