Deploying MVC Paradigm in PHP: Alexandru Liviu Marinescu

Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

Deploying MVC Paradigm in PHP

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.

1.2 MVC Frameworks for web applications


The separation between the three components is very important in a MVC-PHP framework. To make the best use of MVC, the user has to thoroughly understand the relation between the three components and their member classes [3]. Another important aspect of a MVC framework is modularity. PHP has a wide range of available libraries that could be used as one of the three components. It is desirable to let the developer choose what library best suits the project's needs. We will refer this as loose coupling. The advantage of loose coupling is that the framework will need a small amount of glue code to make it work. This way the framework will be easier to learn and use [1]. The framework will provide a basic setup that is easy to chain and customize. Currently there are a set of web frameworks that are built using the MVC paradigm, each having its particularities and offering various levels of freedom when it comes to implementation. With most of the current web frameworks,

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.

2. Technologies and standards


Apart from the MVC paradigm, the current framework will also use other programming design patterns, so that a higher level of modularity and flexibility is achieved. The framework will implement the following paradigms: ORM, Singleton, Facade and Proxy. All the framework's features were thought to ease the development of web applications. ORM is used to have easy access to the application data. This is why the user will only have to create his database and tell the framework what is the model's source[4]. From there the framework will introspect the database to see its tables, structure and properties. Based on these properties the framework will create the appropriate classes to access the database and offer CRUD functionalities. The Model's ORM component will be responsible for data validation, caching and database connection manager. It will offer an abstraction level over SQL and proprietary databases. The developer will not have to write SQL statements. The ORM offers ways of accessing and modifying the database without the need of using SQL statements. Based on the ORM configuration, the framework will decide what drivers to use when connecting to the database. Most of the current web frameworks have the tendency of offering very complex APIs. This can be both an advantage and a disadvantage. The advantage is that the user will benefit from a wide range of classes and functions to develop his application. In the same time his learning curve will be affected and it will take more time for him to accommodate with the framework's API. He will also be more liable to have more bugs in his code. Frameworks with large API are harder to debug because of their complexity and large number of abstraction layers[5]. We try to offer a good equilibrium between the flexibility offered to the user to develop his application and the exposed complexity of the framework API. The Facade is a design pattern used whenever is needed a common interface to a wide set of other interfaces. The Facade defines a higher level interface, which simplifies the developer experience with the system[2]. This way we reduce the number of external code dependencies and enhance the uses of third party elements integrated in the framework. Each framework component uses this design pattern to create a uniform API which is easy to use, understand and extend. The framework's main components wrap in adapters its underlying architecture so that the user will not have to directly instantiate classes that are not relevant to his purpose. The model has a single access point. The developer only has to specify what he wants to access. From there the model will instantiate the needed classes to access the tables involved in that transaction, create the correct SQL query to get the data from the DBMS and populate the model with that data[6]. The controller only has to get the request URL and from there it will decide what controller class he has to instantiate and what action class will have to call. It will also parse all the arguments sent to that page and sanitize them accordingly to a set of rules defined by the developer. The View will only get the name of the template that the user wants to render and the populating data. From there the Facade View Class will instantiate the view parser or get the compiled template from the caching system, populate the template with the correct data and return the result back to the controller, which in his turn will serve it back to the user. Database connections are expensive in terms of systems resources and that's why the framework implements the singleton design pattern to manage the number of database connection. Each model instance will access the database through a connection that is received from the connection manager[6]. This is where the Proxy design pattern is used to decide what type of connection will be used and provide an abstract interface to create and use it. This is what enables the framework to use various database management systems.

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.5 Logging and Error reporting


Logging is highly dependent on the server logging services. The user will be able to use the web server logs to output logging information. The user might also enable file logging, to log users in dedicated logging files. The use of web server logging files is advised because application events will be synchronized with other server events, therefore debugging information will be more complete. There are some common functions between the logging and error reporting modules. These functions will be used to dump variables information and application state information. Logging has multiple levels of output: INFO - general information NOTICE - possible code bugs WARN - warn about possible application errors DEBUG - output debugging information ERROR - output error messages Error and message reporting is made through the flash function. This function registers in the application session a message that is available only in the response page. After the response has been sent to the user, the flashed message is freed.

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.

3.7 General purpose functions


The proposed framework offers a package of functions to work with strings, date types and files. Some of the framework components use these functions found in this package, but they are available for the application developer. The most important type of functions in this package is the autoload functions. These functions enable the developer to use functions and classes defined in the application without the need of including the necessary files. This is done through the binding of a function that automatically loads the application file structure in a tree structure and search for the needed files and includes them when needed. The tree structure is cached between requests to have good access times to it. The autoload function will also load the framework configuration files and instantiate the needed modules, so that the developer will not have to.

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.

Framework file structure


app - framework specific files o cache - cache related files are stored here o docs - framework documents generated using PHPDoc o engine - contains MVC related files controller - controller related files Controller.php - implements the controller WikiController.php - implements a controller that acts like a wiki, when it does not find a page, it will search for one in database dal - database drivers and connection manager DAO.php - Data Access Object Interface MySQLDAO.php - MySQL driver MySQLErrorException.php MySQL driver exception ProxyDAO.php - connection manager model - model related files

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

Framework work flow


When the user enters an URL, Apache will check the framework configuration file in the main directory and parse all the routing rules. After a match has been found, the URL is sent as an argument to index.php where the main controller is created. This is where the URL to Controller mapping is done. After a controller has been found, the arguments related logic is executed, user validation is done and after that the model is instantiated and passed to view module. From there the view is compiled and the result is returned back to the user. index.php includes aqva.php which reads configuration files and sets up the autoloading module (which is has to load the needed classes).

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

You might also like