LogoPhly, boy, phly
the weblog and site of Matthew Weier O'Phinney

Thursday, December 7. 2006

MVC changes in Zend Framework

Several months ago, Andi asked me to take the role of lead developer on a refactoring of the Zend Framework MVC components. I agreed, though somewhat reluctantly; I already maintain another MVC library, and wasn't sure how well I could fill the shoes of people like my friends Mike, who had done the initial development on the controller classes, and Paul, who provided Zend_View.

The experience has been incredibly rewarding, however, and I've had the chance to pick the brains of and work with some top-notch developers in the process. In the next week or so, we'll be releasing version 0.6.0 of the framework, and it will include much of my work in the MVC components as part of the core distribution. A big thanks to all those who have contributed opinions, design help, code, tests, and documentation; another thank you goes to Andi for trusting and supporting me in this endeavor.

So, what are the changes? Read on to find out...

Most of the changes lie under the hood at this point; the most basic usage of the MVC components remains the same. The changes introduced mainly promote greater flexibility and testing. In fact, the most significant changes, the introduction of request and response objects, are transparent to most users, but are the very changes that make unit testing of the MVC components both possible and easy.

So, as you may have guessed, the controller classes are now unit tested; coverage isn't perfect, but it's reasonable (currently around 68% code coverage), and an improvement over the basically zero coverage from before (only Martel's RewriteRouter had tests before I started). What this means to developers is that from this point forward, any changes to the controller classes will need to pass regression tests... and those tests actually exist. It also means that it is now possible to unit test applications without needing a web server; this is going to be a big step for MVC applications based on the framework.

By introducing the request and response objects, we now no longer need to rely on a web environment in order to make requests; having a response object makes it trivial to capture output from the various action controllers and then test against expected results. This is a huge change.

Additionally, by de-coupling the controllers from the request environment, it becomes possible to use the MVC components in non-web environments. Think CLI and PHP-GTK.

Another change is that a router is no longer needed. This allows developers to use the MVC components in non-web environments, where routing may not actually be necessary, as well as to use the MVC components in web environments where pretty URLs are difficult to configure. IIS, for instance, doesn't have a mod_rewrite equivalent out-of-the-box, so being able to specify a url such as http://localhost/index.php?controller=index&action=view and have it dispatch properly is a nice feature.

A feature that many were requesting was the ability to push parameters into the front controller, and have those push through to each of the router, dispatcher, and action controllers. Such an ability would obviate the need for a registry, and also allow the entire controller chain to share an environment. I made use of this today when a request came in for the ability to specify an optional module parameter in the request URI; instead of breaking backwards compatability or creating new routers and dispatchers, I was able instead to simply push a 'useModules' setting through the chain, and if discovered, act on it. (This new feature allows urls such as http://localhost/module/controller/action to dispatch to Module_Controller::actionAction(); think controller classes in subdirectories.)

One feature that I think a lot of people don't understand is the Response object. It is a container for the entire response generated by a request, whether that's from a single or multiple actions. As such, it also aggregates exceptions from the process. It's final purpose is to return that response to the client, and this is done by simply echo()ing it; its __toString() method should take care of any final rendering to perform.

The basic response object provided with the new system does very little. It allows for the setting and aggregation of content through its setBody() and appendBody() methods, as well as setting headers via setHeader(). If exceptions occur, they are registered via setException(). The suggestion made in the documentation is to use appendBody() to aggregate content, and then have __toString() return the aggregated content en masse by echoing the response at the end of the dispatch loop: echo $front->dispatch().

While this is nice, there are some much more interesting things you can do with it. In a recent project I did, I integrated Zend_View and Zend_Json in the response object, and added accessors in my action controllers to push content to the response object. Then, based on the request, I could switch between returning JSON strings or XHTML content. If an exception occurred, I could redirect to an error page, or, in the case of an AJAX request, return an error encapsulated in a JSON string. This type of context switching is very powerful, and I'll blog more about how it can be achieved later.

If you already use the framework MVC but haven't tried the new code, I encourage you to download a snapshot or grab it from subversion and give it a spin; there's a document covering migration, and any feedback or additions on this would be greatly appreciated (this document in the framework wiki is currently out-of-date; check the docbook in the framework distribution you download for more current information).

If you haven't tried the framework MVC, and are interested in MVC libraries, give it a whirl and let me know what you think!

Posted by Matthew Weier O'Phinney in PHP at 23:41 | Comments (3) | Trackbacks (0)

Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)

Matt,
Great job! I'm looking forward to testing out the new MVC components on the sites I've been testing ZF with. Will this address issues that some have that lack mod_rewrite functionality?
#1 Jay M. Keith on 2006-12-08 14:06 (Reply)
Yes and no. Zend_Controller_Request_Http goes a long way towards trying to autodiscover the request URI path, but due to the number of web servers available as well as OS differences, it's certainly not perfect.

However, there are some definite features in the new version that work very nicely towards this. First, a router is completely optional at this point, meaning you can simply pass the controller and action as $_GET parameters now. Additionally, if you setBaseUrl() on the front controller, request, or router objects, you can hint as to where in the URL the router should start looking for elements. So, if your url looks like /some/dir/index.php/foo/bar/var/val, and you specify setBaseUrl('/some/dir/index.php'), it will find 'foo' as the controller, 'bar' as the action, and a parameter 'var' with value 'val'. This works with or without PATH_INFO being available, which makes it much more portable.
#1.1 Matthew Weier O'Phinney (Link) on 2006-12-17 14:38 (Reply)
Hi Matthew,

I'm really impressed by the work you're doing. This article gives me a clue on the way I could solve my current problems.

If you don't mind, I'm going to try to expose them.

In the past, I worked on intranet applications based on many pages calling one by each other.

But now, i'm working on an application with two main screens (or pages).

So, I realize I can't keep working on a page controller model as I don't want to reload the entire page after each action.

I chose to use Ajax requests and then to update the current page with the server response. But the problem I'm stuck on is that one action could update different part on my interface.
Let's say my interface has three zone (z1, z2, z3), and an action triggered from z1 may update the z1 content as well as z2 content. Moreover, sometimes I need xhtml responses and sometimes I want to json encode the response.

So, I decided to use the response object as a container. I extended it creating my own response object. I push in it a list of templates I will render and an array of data used by the templates or just encoded in order to echoed json strings. Then after the front controller dispatch loop, according to the request object, I render the smarty templates or just encode the data.
It works but I made a very dirty implementation, I just couldn't figure out how to modelize it in a clean way in the action controllers process.

While surfing on the web looking for the graal, I read your article and I read this magic sentence :

"In a recent project I did, I integrated Zend_View and Zend_Json in the response object, and added accessors in my action controllers to push content to the response object. Then, based on the request, I could switch between returning JSON strings or XHTML content."

I think it's THE solution I'm looking for.

Then, you wrote :

"I'll blog more about how it can be achieved later."

So I would like to know whether you still planning to do so in a near future or as you might be really busy by now :), you decided to leave it aside for the moment.

Anyway, thank you for the great job you're accomplishing on the framework, I enjoy everyday using it.

regards,

Fred
#2 fred on 2007-03-08 05:41 (Reply)
hello, Mr Matthew.
i can not send a email to you, so i post my question on here,sorry:-)
I am a newer of Zend Framework, i write a program to test the speed of
Zend Framework, code like this:

/var/www/htdocs/index.php


/var/www/app/controllers/IndexController.php


my .htaccess file is:
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
php_value include_path "/var/www/lib/ZendFramework/library"

i use "ab -c 5 -n 1000 http://localhost/", it show me 32.27
requests/sec, but if i write a php program direct echo 'hello, world',
it can handle 2004.32 requests/sec.

how can i Optimizate my program of zend framework version?

thanks
#3 hzqij on 2007-03-11 12:35 (Reply)

Add Comment

Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
 
  • Home
  • Resume
  • Blog
  • Phly PEAR Channel
  • Contact Me
  • About this site

ZCE

Zend Education Advisory Board Member

Add to Technorati Favorites

Calendar

Back July '09
Mon Tue Wed Thu Fri Sat Sun
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Quicksearch

Links

  • PHLY - PHp LibrarY
  • Paul M. Jones
  • Mike Naberezny
  • Shahar Evron
  • Planet PHP
  • Zend Where I now work
  • Garden.org Where I once worked

Archives

July 2009
June 2009
May 2009
Recent...
Older...

Categories

XML Linux
XML Personal
XML Aikido
XML Family
XML Programming
XML Dojo
XML Perl
XML PHP

All categories

Syndicate This Blog

XML RSS 0.91 feed
XML RSS 1.0 feed
XML RSS 2.0 feed
ATOM/XML ATOM 0.3 feed
ATOM/XML ATOM 1.0 feed
XML RSS 2.0 Comments

Show tagged entries

xml best practices
xml books
xml conferences
xml decorators
xml dojo
xml dpc08
xml file_fortune
xml linux
xml mvc
xml oop
xml pear
xml perl
xml personal
xml php
xml phpworks08
xml programming
xml ubuntu
xml vim
xml webinar
xml zendcon
xml zendcon08
xml zend framework
© 2004 - present, Matthew Weier O'Phinney
matthew-web <at> weierophinney.net