Table of Contents
I've spoken to a lot of developers over the years and the primary concern they've voiced about adopting web application frameworks is understanding the architecture of those frameworks. Nearly all web application frameworks have adopted an architecture first described in 1979 by Trygve Reenskaug called Model-View-Controller (MVC). It might be an old idea but its recent revival in web applications seems to fit like a glove, more so than it ever did in desktop applications.
In PHP, there is a lot of misunderstanding surrounding MVC. Many developers see it as being overly complex, difficult to understand and not worth the effort. The same people often label frameworks using MVC as time consuming, performance damaging or bloated with unneeded features and source code. While I understand those sentiments they are not entirely true since MVC is actually quite a simple concept. In fact it is now regarded as one of the cornerstones of what has made web application frameworks so popular.
Since it is nigh on impossible to understand the Zend Framework without a working grasp of MVC it needs to be explained up front. This is not a chapter you want to skip! The first thing to remember is that MVC is not a specified implementation, rather it's a loosely defined pattern of behaviour whose implementation varies depending on the goals of the framework, the application and the programming language being used. This concept of a named general solution to a programming problem where the implementation is not specified but described in general terms is known as a Design Pattern. We'll see more examples of how Design Patterns enable understanding of framework architecture in later chapters.
As a bit of background, consider the historic use of PHP in crafting dynamic web pages. The typical approach is often referred to as the Page Controller (there's also Transaction Script but you can't explain total chaos reliably!). The Page Controller is another Design Pattern described by Martin Fowler in his famous book "Patterns Of Enterprise Application Architecture" (fondly abbreviated to POEAA in the community). It describes an approach where each HTML page of your application may have its own dedicated PHP file. Often it ends up as many HTML pages per PHP file, but only if those pages are sufficiently similar (e.g. forms and form processing are typical similarities) that the relationship is formed out of the need to reuse source code in the same file. Frequently these pages will have common includes at the top to handle importing libraries or constants. All pages may need Smarty, for example, or a database connection.
In this scenario however, it becomes quite difficult to manage growth and change. Every new feature or bug fix requires additional code and where you end up putting that code becomes a major factor which influences the maintainability of your application. Perhaps a small change requires several changes to multiple pieces of business logic which over time have been distributed across a dozen or more files such that you end up duplicating sections of source code. Perhaps you discover that SQL statements in another dozen files all refer to a table name which is being altered. You can imagine the profusion of small changes such as these across multiple files exploding exponentially until you realise that merely maintaining this mass of source code takes a lot of time and resources. This is the point at which many projects simply stagnate despite the enthusiasm of its developers. I've fallen into this trap myself, and witnessing it first hand was what encouraged me to seek out a better approach.
Over the years, PHP application development has undergone a few important revolutions. The most important was the widespread adoption of Object Oriented Programming (OOP). A second was the adoption, slow but steady, of best practices enabled by OOP such as Unit Testing. A third was the explosive increase in use of the Model-View-Controller architectural Design Pattern and its influence on the current generation of web application frameworks like the Zend Framework.
The Model-View-Controller architecture (usually abbreviated to MVC) is a general solution or Application Design Pattern to the question of how to separate the responsibilities in an application in a highly structured manner. Basically it avoids total chaos!
Its purpose is to prevent dissimilar code from mixing uncontrollably, emphasising that there are three component types which should cooperate at a distance through a set of interfaces. While that sounds horrendously complex (don't worry!), it prevents source code from collapsing under its own weight into the infamous spaghetti mess characteristic of many disorganised PHP applications.
The name of this architecture mentions all three of the component separations: Model, View and Controller. Although MVC may seem to be one of those esoteric concepts in programming, it's actually quite a simple concept.
You pick some nugget of functionality, determine its purpose, assign it to one of the three separations, and finally to a specific class within that division. Once everything is split correctly, you end up with an application composed of smaller pieces which are reusable, centralised, accessible, and fit together like building blocks exposing an abstract API to let them link together - working now with abstracted APIs makes incremental changes extremely simple (if done correctly of course!). With everything tidily organised into objects with specific responsibilities, the cost of change is normally reduced significantly which is really the whole point - we want change to be cheap, easy and horror free.
Obviously I'm not covering the entire field of Object Oriented Programming here. But hopefully the message is sufficiently clear. MVC ultimately reinforces all the benefits good OOP practice should generate. Code adheres to principles like Don't Repeat Yourself (DRY) and Keep It Simple Stupid (KISS) which discourage messy duplication and enhance reuse and maintainability.
The one thing which confuses developers though, is that MVC seems to create more code than if you didn't use it at all. This isn't a symptom of MVC being bad, it's a common effect of applying Object Oriented Programming and a well known outcome of the increased structure. When using a web application framework however that problem is not yours. You're not writing the framework from scratch now, are you? Another reason for an increased amount of code is fairly obvious - frameworks add a multitude of features beyond what a simple MVC implementation would offer.
However, since OOP does create lots of classes, you should understand why that's a good thing. A massive procedural script would have less code, and even be a lot lighter on its feet, but it's not a permanent solution. OOP code is designed to significantly decrease the cost of maintenance, testing, adaptation and reuse. These normally far exceed the up front cost of development! Remember, you will have to live with that crazy code for years. Write once, use forever. Constantly recreating solutions is not a sustainable method of development since instead of having immediate sunk costs you'll never see again, you have continually escalating costs with each new reinvention of the same old wheel under a different guise. Rewriting or reinvention is expensive and also risky.
The Zend Framework,
being a glue framework, offers MVC in a componentised form. This means the
framework's MVC architecture is split across a number of apparently
independent components including, but not limited to,
part of a Model,
Zend_Layout. Each component covers a specific role
within MVC but retains all the characteristics of independent components
you can use outside an MVC architected application.
This all certainly results in a profusion of focused classes to such an extent that it can become difficult to see how all the pieces work but honestly you only need the outer abstracted API of each component and can ignore the rest unless you really really want to customise something. For every commonly used class method, there are probably another five only a minority of developers will be interested in. This emphasises the Zend Framework's adaptability - the extra methods exist so you can customise the framework should the need arise (and it nearly always does unless you like restrictive pigeon holes).
Let me enforce one other
point to erase any lingering doubts. MVC is as common as dirt. Nearly
every modern web application framework utilises MVC. It's used in the Zend
Django for Python,
Ruby On Rails and
Merb. Pick a framework and
odds are it will describe itself as an MVC framework!
Let's meet each MVC component!
The View is responsible for generating a user interface for your application. In PHP, this is often narrowly defined as where you put all your presentational HTML. While this is true, it's also the place where you can create a system of dynamically generated HTML, RSS, XML, JSON or indeed anything at all being sent to the client application whether a browser or some requesting web service. Such generation usually takes one or more Models as the source of the dynamic data the View is generated to present. We can't be too strict though, the View can also accept simple data like scalars and arrays so don't start wrapping every smidgen of data in a Model if it's not required.
The View is ordinarily organised into template files but it can also simply be echoed from, or manipulated by, the Controller prior to output. It's essential to remember that the View is not just a file format - it also encompasses any PHP code or parsed tags used to organise, filter, decorate and manipulate the format based on data retrieved from one or more Models (or, as is often the case, passed from the Model to the View by the Controller).
A second facet of the View is that since all content is generated dynamically by PHP, it is entirely reasonable to create custom plugins within which to capture frequently used tasks. For example, when translating the title of a blog post into a URL friendly format it's necessary to remove some punctuation and replace non ASCII characters with their ASCII equivalents. This task could easily become a View plugin that operates on the text title of the entry when adding URLs to your templates. We know such plugins belong to the View since they represent presentation logic - logic whose sole purpose is to manipulate the presentation of data.
On a side note, this book will not require Smarty or any other standalone library for interpreting templates. Smarty has a respected history in PHP but it does have serious failings once you start thinking of the View as a jigsaw puzzle of potentially dozens of reusable pieces pulled together into a single overarching layout. In effect, this method of View management is so closely related to OOP as a concept that using PHP itself as a templating language becomes almost inevitable. That's not without a cost though since not all web designers know PHP but the Zend Framework does allow you to integrate whatever templating engine you prefer.
Controllers are almost deceptively simple in comparison to the View and Model. The primary function of the Controller is to control and delegate. In a typical request to an MVC architecture for the web, the Controller will retrieve user input, translate it into actions on one or more Models, and return output generated by the View based on the results of those Model actions.
Now, I'm going to immediately point out that this workflow emphasises an important fact about Controllers. Controllers delegate as much as possible because if you overload them with responsibility they will quickly become overburdened and a pain to maintain. In fact they'll start to dangerously resemble the age old Page Controller approach which is BAD(TM). Application logic should be delegated as much as possible to Models. We'll meet Models next, and we'll dig more into the concept of Models in Chapter 3.
The Controller also has a unique difference from other forms of PHP architectures since it only requires a single point of entry into the application - almost inevitably called index.php. The existence of one route into an application makes certain tasks a lot easier. For example, you can set up a chain of request filters which execute on all requests. Access Control Lists (ACL) are a prime example of one common filter. Hooking in an application firewall or honey pot (security layers) is another. In fact we'll meet a little known project called the PHP-Intrusion Detection System (PHPIDS) at some point in a later chapter.
The Model can be explained a few ways. In fact, you can write entire books about just the Model and many people have! Chapter 3 delves into this realm in far more detail but let's cover it quickly here.
The Model generally has two roles broadly defined:
1. The Model is responsible for maintaining state between HTTP requests.
Basically any data whether on a database, in a file, stored in the Session, or cached inside APC must be preserved between requests and thus forms part of the state of the application at the time the last request was completed. So always remember that the Model is not just the database. Even the data you get from web services can be expressed as a Model! Yes, even Atom feeds! Frameworks which rattle off introductions to the Model, almost never explain this upfront which only exacerbates misunderstandings.
Here's an example,
Zend_Feed_Reader which I developed with Jurriën
Stutterheim is actually a Model. It reads feeds, manipulates them,
interprets data, adds restrictions and rules, and generally creates a
usable representation of the underlying data. Without it, you have
Zend_Feed (the current top dog in feed reading)
which requires lots of additional work to develop it into a viable
Model. In other words, where
a partial Model,
Zend_Feed is pure data
2. The Model incorporates all the rules, restraints and behaviour governing and utilising this information.
For example, if you wrote business logic for an Order Model in an inventory management application, company internal controls could dictate that purchase orders be subject to a single cash purchase limit of €500. Purchases over €500 would need to be considered illegal actions by your Order Model (unless perhaps authorised by someone with elevated authority). The Model should be capable of enforcing this constraint.
This makes incredible sense if you examine the meaning of the word "model". We have climate models in climatology, for example, which define the data, run processes, assume behaviours and calculate probable outcomes from these. The M in MVC is called a Model for a reason. The Model doesn't just represent mere data, it represents the entire system for which that data is useful. Of course any system can be complex enough to require multiple interacting Models but you get the idea.
If you read these two points, you may realise something startling. With the exception of the UI, most of an application can be expressed within Models. It's the Model that centers on all the data and underlying behaviour of that data, and sometimes even how to display that data. It's the Model which can understand, interpret and represent that data and provide it with meaningful uses. It's also a logical place to store validation rules and constraints - why not keep those with the data they operate on?
This examination makes
it obvious that the Model is the one part of the MVC tripod you need to
develop almost from scratch. The Zend Framework can provide data access
components, but it can't predict what your application will do! Since
Models go beyond mere data access, a lot still needs to be developed and
tested before you have a viable Model. It's not always as easy as
We'll cover the Model further in Chapter 3 since there is a wealth of information to consider about what it represents, and where it fits in the overall MVC picture.
The Model-View-Controller architecture has become a widely recognised solution suitable for web applications and it's evident in the majority of the current generation of frameworks for most programming languages.
In the Zend Framework,
these three separations are represented by the
Zend_Controller components. You'll be hearing a lot
about these four framework components and the classes they are composed of
in the chapters to come! Together these form the backbone of the Zend
Framework's MVC architecture and underpin a lot of its best
MVC was originally used to promote the "separation of concerns" in desktop GUI applications. By separating each concern into an independent layer of the application, it decreased coupling and interdependencies which in turn made applications easier to design, write, test and maintain. Although GUI applications have turned away from MVC in recent years, it has proven to be highly effective when applied to web applications.
In the framework this
adds a lot of predictable structure since each segment of MVC for any one
supported request is segregated into its own group of files. The
Controller is represented by Zend_Controller_Front and
Zend_Controller_Action subclasses, the Model by domain classes or another
set of classes which may rely on
Zend_Db_Table_Row for database persistence, and the
View by .phtml template files and View Helpers. The Zend Framework manages
how each is orchestrated in the big picture leaving you free to focus on
just those groupings without worrying about all the code combining them
together into a cohesive work unit.
In a sense it's like building a house where the foundations, walls, internal wiring and plumbing are already in place and all that's left is the internal decoration and a roof. It may take some time to learn how to decorate and roof the prepared sections but once you have learned how, later houses are finished a lot faster!
This was a quick assault on the concept of the Model View Controller (MVC) architecture. Despite its length it's not an exhaustive examination but it covers enough ground that later concepts won't be completely out of context. Outside this book there exists a flood of articles concerning the ins and outs of MVC on the internet and elsewhere and I encourage you go find some because it will not be wasted time. Every bit of understanding is worth the time you spend finding it.
In the next chapter of this journey we'll spend some time getting to know the Model. It's treated separately since the Model can pose a lot of difficulty as a concept and it has a wide range of uses.