Deploying MVC Paradigm in PHP: Alexandru Liviu Marinescu
Deploying MVC Paradigm in PHP: Alexandru Liviu Marinescu
Deploying MVC Paradigm in PHP: Alexandru Liviu Marinescu
AlexandruLiviuMarinescu
Abstract. This article describes a framework implementation built using the Model-View-Controller programming paradigm in the PHP programming language. MVC is best known for its use in creating extensible application with rich user interfaces, but we will present ways it can be enhanced to be best adapted for a PHP environment and web applications and websites. We present the framework architecture, implementation aspects and plans to enhance its usage.
1. Introduction
1.1 Paradigm Overview
An application that implements the MVC paradigm is split in three main components: Model, View and Controller. Each component has its own purpose and it has to be designed in such a manner that a change in its logic will not affect other components. Components have classes that provide services for the outside world. The view will manage the graphical and/or textual output [3] of what the controller decides to gather from the model. The model manages application's data domain. The Model is the central point of the application. The view gets information from the model, based on the decisions made inside the controller. The model's purpose is to create a representation of the problem that is trying to be solved. The model is aware of the existence of the other two components by providing proper interfaces for its initialization, access, modification and deletion. Any related logic of these actions should only be made through the model's methods. The View will present to the user the pieces of information gathered by the controller from the model classes. It should only contain presentation code and no decision making code. It has to be able to adapt the presentation format in regard to the user input and capabilities. The Controller will have to make decisions based on the user input and behavior. It has to initiate the model according to the application requirements and specification. The Controller will have other responsibilities: validate user's input (even if this might be a task that could be performed by the model), authorize/authenticate the user, route the user to the correct part of the application. In order to have a working application the three main components must communicate with each other [3]. The controller and the view can communicate directly, whereas the model will have a thinner communication layer with other two, since it main purpose is to provide data management services.
a web developer has to overcome the difficult deployment, hard to maintain configuration files, integration, limitations in code expressiveness. Nowadays, most web frameworks are popular because they provide a structure to ease the creation of web applications. They accomplish this by either providing code generation mechanisms (form generation, model class generation) or by providing introspection mechanism for the model's data sources so that the developer will have to spend less time defining and programming it. The current framework is built using the best of both worlds.
Caching is never handled directly by the user. He only has to configure the application as having caching enabled and from there the model will take care to correctly get information its database or the cache (when necessary or appropriate, the cache has not expired and/or an instance is available). Currently the caching system only supports memcache, but it implements a proxy approach, similar with the way the model handles multiple DBMS types, so that other caching mechanism may be added. Aside from the enumerated design patterns, the framework also implements other mechanism to further enhance the application performance. The Model has embedded mechanisms of lazy/eager loading and updating. Lazy loading is enabled by default in the Model. This means that when the user queries Model classes, they will not immediately load the data from the database[3]. It will return a reference to an object that will load the information when the data is needed. When the data is accessed the model will load the data accordingly to the data loading size. This means that data can be extracted row by row, multiple rows at the same time or the whole result in a query. Eager loading, on the other side, will load the entire result from the database in a single database access, when the query is created. The decision, about which loading policy to use when loading data from database, is left up to the user, even thought lazy loading is set as default. Lazy/eager updates are mechanisms that work in a similar way with the lazy/eager loading mechanism. These policies will decide the moment when a update is triggered in the DMBS. With lazy update, operations will be executed after the whole controller has ended. With eager update, the update is triggered at the same time with the update operation made inside the controller. Web application security is handled by data validations and the authentication and authorization module. Both modules are using an internal micro-programming language. This micro-programming language is used to define variable types and properties. A variable can be an argument sent to a controller or a user identity, group or permission. The language is tightly coupled with the logging and error reporting modules. Validation errors found in the application variables can be logged or sent to error reporting pages.
3. Framework architecture
The framework has the following modules: Model - models application data View - templates, styles and Javascript Controller - binds the model with the view Logging and Error reporting - log application events and errors Validation - validate user input and page arguments General purpose functions - functions with various purposes used across the framework
3.1 Controller
All HTTP request are directed towards the routing page. The routing page will instantiate the main controller class. The web application is structured like a tree. A node in the tree is a controller and a leaf is an action inside a controller. A controller can have one or more leaf and controller nodes. The tree has no height limit. If an URL cannot be mapped on a controller, then the deepest existing controller found will call its default function. This mechanism offers good application flexibility, because it can allow the implementation of various applications e.g. a wiki: whenever a page is not found in a controller structure it can be searched in the database and if it is not found there, then the controller can show a form to create the page. A mapper can be attached to a controller to enhance its routing capabilities. The mapper has an array of rules. Each rule has two components. One component contains a pattern that the URL has to match to select that rule and the second part is an action (that is composed of a controller class and an action inside that controller).
3.2 Model
The model has multiple layers. The bottom layer is made of different database drivers. When a new connection is made the application decides what driver to use to connect to the database. The decision is based on the database configuration URI. This URI has the format 'driver://user:pass@server/database? arg-1=val-1&'. The URI specifies what database driver is going to be used, what credentials to use when the connection is made to the server and what database to select from the DB server. A driver is responsible for correctly formatting query strings, create and/or open a connection to the database server and execute queries. On top of the drivers layers is the connection manager. The manager will create a pool of connections to be used across requests. This way, connections are recycled between requests. Drivers plus the connection manager compose the Data Access Layer. On top of this layer the ORM is built. The ORM models column tables and tables. Each model class will have to inherit the Table class to be ORM enabled. Since the framework mainly uses conventions over configurations, a class that wants to model a certain table must have the same name as the target table. If the name is not available, then the developer can name the class the way he desires and set the property tablename as the target table name. To specify relations between tables, the developer will have to override the function definition. Here one-one, oneto-many and many-to-many relations can be set. When a model class is created, the model will analyze the target table and set up a validation mechanism. If a field is set-up and does not respect the target column properties are not respected, then an exception is thrown. If the developer desires, he can disable model validation. If caching is enabled, when a new query is triggered the cache is first checked for an existing entry. If the cache has the required data, then it will be taken from there, if not, the normal creation process is followed. Caching has a good impact over performance and that's why it is enabled by default.
3.4 View
When the Controller has finished, it will have to return the result embedded in xHTML or any other format, like JSON or xml. The framework is very flexible when it comes to the output formats. The controller will publish the chosen variable by the user, in the template. From there the developer can place variables in the template wherever he wants. The template is included as a PHP page, therefore all language constructs are available inside the template page. In the future, the framework will implement a TAL engine (template-attribute-language) with a set of predefined formatters. Each formatter will output data in a certain kind of format, for example a xml formatter will be used to output valid xHTML and XML. Another formatter can be used to output JSON. These formatters will offer more flexibility in terms of the supported output types. PHP instructions are passed as XML attributes. This kind of approach has multiple advantages. The template can be modified in xHTML/XML editors by persons that do not know programming. The parsed template can be cached to enhance performance, templates will be more readable, easier to design and maintain.
3.6 Validation
Validation is an important component in this MVC framework. This is why the developer has a wide range of options when it comes to data validation. He can choose to let the framework do validation when information is inserted in the model. When a model receives new data, it will use the introspected data schema and validate the data with that schema. If the information is not valid then a validation exception will be thrown. This policy offers a easy to use validation system, but validation goes as long as database type definition goes. If the user desires a more advanced validation schema, then he will have to use the data validation micro-language. The data validation micro-language lets the developer to define advanced validation scenarios. Primitive data types are available. The user can check variables length, if they match a given regular expression or if they are in a certain mathematical relation with other variables. A variable can be an argument sent to a controller, a user, a user group or user permission. The micro-programming language is easy to learn since its syntax is almost the same with PHP, having small syntax sugar additions. The micro-language is tightly coupled with the error reporting system. The user can group statements to output a certain error message when validation fails inside the group.
When the controller is created, all arguments sent are cleaned to avoid most of the known attacks: SQL injection, XSS, XSRF etc. After arguments are sanitized, the validation schema is checked. If the arguments don't pass the validation stage, the user is redirected to an error reporting page. If arguments are valid, then the controller will check the user's credentials. For this the identity module is used. The identity module authenticates the user and loads the user's groups and permissions. Some pages are available to all users, other pages are accessible to users that belong to a certain group, have a particular permission or a combination of those. Using the data validation micro-programming language, the framework can create complex credential checking schemes. The developer can check a user permissions and groups. He can also check user groups or permissions without having to know the database structure that models this part of the application.
4. Implementation
The current framework is implemented on top of Apache web server, PHP 5.2 or above. Currently it only has implemented the access driver for MySQL 5 or above. As we have talked before, the framework uses convention over configuration and this is why a normal application using it, will have a predefined directory structure.
o o
*Exception.php - various exception files HasManyAssoc.php - one-to-many association implementation ManyToMany.php - many-to-many association implementation ModelIterator.php - iteration implementation over a collection of model instances ModelValidators.php - definitions of the validators that can be attached to a table column TableColumn.php - implements a table column and various operations Table.php - implements a table. This is the main class of the ORM. view - view related files logs - applications log files are stored here utilities aqva_texy.php - wrapper around Texy args.php - functions to manipulate request arguments autoload.php - autoload module cache.php - cache module create.php, take.php - facade file for Model general.php - various functions identity.php - identity module log.php - logging and error reporting module schema.php - validation schema functions string.php - string utilities uri.php URI parsing functions
.htaccess - Apache configuration file aqva.php - instantiate autoloading module and prepare the application config.php - configuration file with global configuration variables index.php - the application's entry point www - application specific files o controllers - application's controller classes o lib - contain applications libraries o static - contains applications static files: images, CSS, Javascript o templates - template files o tmp - place where temporary files should be stored
5. Conclusions
Using a framework eases application development and deployment in PHP. MVC is a good choice when it comes to implement web applications in a short period of time thanks to its clear distinction between modules. Using MVC web applications can benefit from a clear separation of business data in a module which is independent of the output format. MVC has appeared in the 80's and now is becoming again a mainstream design pattern to develop solid web applications.
By using appropriate design patterns and best practice techniques, the proposed framework enhances applications development, reduces the number of code bugs and increases application flexibility and modularity. Because it was thought with loose coupling, the framework can easily integrate third party modules and libraries. With the use of a custom template engine, the developer can choose from a wide range of output formats, which accommodate various types of clients. Performance is further enhanced with the caching system. The framework caches model instances and compiled view templates.
6. References
[1] Steve Anglin and Matt Wade. The Definitive Guide to Pylons. Apress, 2009 [2] Jan Bosh. Design Patterns as Language Constructs. 1998. [3] Steve Burbeck. Applications Programming in Smalltalk-80: How to Use Model-View-Controller (MVC), 1992. [4] Mathias Veit and Stephan Herrmann. Model-view-controller and object teams: a perfect match of paradigms. 2003 [5] M. Oliver, T. O'Shea. Using the Model-View-Controller Mechanism to Combine Representations of Possible Worlds for Learners of Modal Logic, Open University, Walton Hall, Milton Keynes, MK7 6AA [6] Patrick Sauter, Gabriel Vgler, Gnther Specht and Thomas Flor. A ModelViewController extension for pervasive multi-client user interfaces. Springer London. 2004