Hostname matching with Zend_Controller_Router_Route_Hostname

Friday, April 2nd, 2010

The Zend Framework offers and handy little tool for hostname matching. This means that you can introduce variables into your application’s URIs. For example, you may want to let users go to a URI like http://chris.yoursite.com or http://neil.yoursite.com and then use the “chris” or “neil” part to determine what content is displayed.

The first thing you have to do in order to use hostname matching, is to setup your server such that *.yoursite.com resolves to wherever your ZF application is running. In most cases this is probably just your domain. For example’s sake, let’s say we setup our server so that *.yoursite.com resolves to the ZF app running at yoursite.com

Once that’s in place, you can start using Zend_Controller_Router_Route_Hostname. Defining a hostname route is pretty straightforward:

 
$hostnameRoute = new Zend_Controller_Router_Route_Hostname(
    ':username.yoursite.com',
    array(
        'controller' => 'profile',
        'action'     => 'index'
    )
);

So what is happening here is that you’re telling the router that any time it see’s something like chris.yoursite.com, to take the “chris” part and store it in a variable called username, then route to the index action of the Profile controller. If you’re familiar with ZF and defining routes, this will seem pretty trivial.

Here’s where things get tricky. Our $hostnameRoute is matching the hostname, so this route will match any path since the hostname will be part of any path for your site. This is where route chaining comes into play. If you’re not familiar with route chaining, I suggest you read the Zend_Controller_Router_Route_Chain section of the ZF manual. You can find it here. The point of chaining the routes is so that you can first match the hostname and then match any number of subsequent routes.

Let’s put this all together with a concrete example, craigslist.org. When you go to craigslist.org it gives you the option to go to URIs like toronto.craigslist.org or ottawa.craigslist.org. From there you get URI’s like toronto.craigslist.org/msg and ottawa.craigslist.org/msg. What this means is that we want the hostname matching to be applied to _every_ URI first, then we’ll match the path to a route.

 
// let's load all the routes for the site (i like to use an ini file)
$routerConfig = new Zend_Config_Ini(
    APPLICATION_PATH . '/configs/routes.ini',
    APPLICATION_ENVIRONMENT
);
 
// create a new instance of the router
$router = new Zend_Controller_Router_Rewrite();
 
// add all of our routes into the router
$router->addConfig($routerConfig, 'routes');
 
// create our hostname route for our site
$hostnameRoute = new Zend_Controller_Router_Route_Hostname(
						':city.craigslist.org',
						array(
						      'module' => 'default',
					              'controller' => 'index',
					              'action' => 'index',
					          )
      					);
 
// loop through all the routes in the router and create
// a chain with the hostname route
foreach ($router->getRoutes() as $key => $route) {
 
	// this will overwrite the existing route with our route chain
	$router->addRoute($key, $hostnameRoute->chain($route));
 
}
 
// lastly, set the router on the front controller
$frontController->setRouter($router);

And that’s all there is to it. The trickiest part is getting the hang of the route chaining – once you’ve got that down, you’re good to go.

Book Review — Zend Framework 1.8: Web Application Development by Keith Pope

Monday, March 1st, 2010

I was recently approached by a representative from Packt Publishing to review their newst book on the Zend Framework, Zend Framework 1.8: Web Application Development by Keith Pope. The book is intended to be an introduction to the Zend Framework (ZF), and with the exception of chapters 4 and 5, I tend to agree. Chapters 4 and 5 do have their necessary place in the book, it’s just the nature of the content that leads them outside the realm of the introductory. The early chapters are a clear and concise introduction to the ZF and are even useful for the experienced ZF programmer offering a few tidbits and easier ways to do things in light of the 1.8 release. The later chapters are the most valuable for the experienced programmer and set a benchmark for the beginning programmer, showing them an example of how ZF is deployed in real world situations.

Anyone who has been following the Zend Framework and the speed at which they push out releases, may ask if this book will still be relevant. My answer to that questions is a definite yes. The 1.8 release was a milestone release for the ZF; currently at version 1.10, there haven’t been a number of signifcant changes since version 1.8. However, version 2.0 of the ZF will offer and number of changes and upgrades to a number of the core components. At that point, this book will need to be updated and improved, though just enough to get up to the 2.0 spec.

Before jumping into the review, you may want to check out the table of contents or a sample chapter.

The preface and first chapter of the book really highlight how easy it is to get a simple application up and running using the ZF. Within 3 pages of the first chapter, you’ve already got a functioning application (provided you’re following along with the examples). An important part of the first chapter, not only for programmers new to ZF but also those who are just new to the 1.8 release, is the new application configuration and the introduction of the Bootstrap classes. The way of bootstrapping applications changed pretty drastically in ZF 1.8 and you’ll see the important role is plays in development throughout chapters 1 – 4.

Chapter 2 covers all the basics of the ZF Model-View-Controller (MVC) architecture. You’ll probably need a little bit of background information about MVC architecture in order to get a full grasp of what’s going on here, but even without any knowledge of MVC, you should be able to continue following along. Really only the View and Controller ascpects are covered in any detail in Chapter 2. The Model aspect comes to light in chapter 3 and finds fruition in chapters 4 and 5. Chapters 4 and 5 start to delve outside of an introduction to the ZF and get into some of the more complex aspects of application development. In these chapters you start to see more of a picture of how Keith Pope builds a web application, which is understandable, an authors background is going to influence their writing. However I don’t think that the Service Layer pattern is strictly necessary for an introduction application development. I think that someone new to the ZF should probably re-read these chapters after reading the entire book and building at least one application. I think the importance of these chapters will come to light in retrospect.

Chapter 6 is a brief but very useful introduction to the Zend_Form component, which is arguably one of the more powerful aspects of the ZF when building web applications. While chapter 7 brings together the View aspect of the MVC showing the role that the forms play within views and really emphasising how ZF can speed up your application development. Chapters 8 and 9 cover some of the more complex parts of any web application: Authentication and Authorization. Authentication and authorization are two concepts that are often confused or conflated. Pope defines them very succintly by asking a couple simple questions to the requesting user. Authorization asks: “Can they do this?”, while Authentication asks: “Are they who they say they are?”. It’s important to keep these two concepts straight. The ZF’s concept of modules is introduced in chapter 10. Modules are a way for you to compartmentalize your application and can be reused between different applications. If your application is setup properly, modifications are only required to the application’s bootstrapping.

I found chapters 11 and 12 to be particularly useful, especially for the experienced ZF programmer. Chapter 11 covers the powerful caching that the ZF is capable of. ZF offers a number of different caching strategies, each suited to a particular purpose. Chapter 12 gets into the nitty gritty of testing. Testing is one of the most important aspects of web application development, especially when your application is live and used regularily. Pope gives a quick and handy introduction to PHPUnit (one of the most widely used testing frameworks for PHP) and then shows how ZF extends the functionality of PHPUnit. Ultimately at the end of chapter 12, you have all the tools necessary to test your entire application.

After getting through this book, you will have more than the tools necessary to build out a powerful web application using the Zend Framework. If you would like more information about the book or are interested in purachasing it, you can check it out on the Packt Publishing website

Using Zend_Soap_Client with the Campaign Monitor API

Wednesday, February 3rd, 2010

I recently needed to write a PHP client to integrate with the SOAP side of the Campaign Monitor API. The code was pretty simple and straight-forward, but I was getting a weird error: 101 Invalid ListID. I checked and re-checked my ListID in our Campaign Monitor account and verified that I was using the correct ListID. Why then was I getting this Invalid ListID error?

After reading the Campaign Monitor API documentation a couple times, I realized that there was a specific header that I wasn’t using:

SOAPAction: "http://api.createsend.com/api/Subscriber.AddWithCustomFields"

Due to the Invalid ListID error, I wasn’t even thinking about headers! To fix the problem, all I needed to add was one line of code:

$client->addSoapInputHeader(
        new SoapHeader($soapUri, 'SOAPAction', $soapUri . $action)
    );

Then everything worked! Awesome.

Here’s a full code snippet:

 
$wsdl = 'http://api.createsend.com/api/api.asmx?wsdl';
$soapUri = 'http://api.createsend.com/api/';
$apiUri = 'http://api.createsend.com/api/api.asmx';
 
$apiKey = 'xxxxxxxxxxxxxxxxx'; // replace with your API key!
$listId = 'xxxxxxxxxxxxxxxxx'; // replace with a valid ListID! ;)
 
$action = 'Subscriber.Add';
		$method = 'AddSubscriber';
 
$client = new Zend_Soap_Client($wsdl);
$client->addSoapInputHeader(
        new SoapHeader($soapUri, 'SOAPAction', $soapUri . $action)
    );
 
$params = array ('ApiKey' => $apiKey,
		 'ListID' => $listId,
		 'Email' => 'test@offshootinc.com',
		 'Name' => 'Test Testford');
 
$response = $client->$method($params);
 
$resultName = $action . 'Result';
 
print_r($response->$resultName);