Tag Archives: Zend Framework

Running Zend Framework modules from a Phar file

Using Zend Framework as an MVC application is probably the most common usage examples for Zend Framework. When you create such an MVC application, you will probably have heard about modules: reusable components of your application. Ideally these modules are drop-in and require little or no configuration before you can use them. This way you don’t have to recreate the same old “news module” for every client or customer. In my case, I usually just copy and paste the module from one base project into a new project. That’s easy. But it would be cooler to package your module as a Phar file, and run that file instead.

Bootstrapping Phar modules

Unfortunately, there is no support in Zend Framework 1.x for running a module from a Phar file. But we can build that support ourselves! With a little knowledge about bootstrapping, we can integrate Phar support for modules.

During the bootstrapping process, so called resources are used to prepare the application for running. A lot of resources are readily available, like a database resource for your database connection, cachemanager for configuring caches, … And there is a “Modules” resource. This one takes care of bootstrapping each module. The purpose of bootstrapping a module, is mainly to get the module namespace known in your application and to tell the FrontController where it can find a module.

This built-in modules resource loops over each directory it finds inside the specified modules folder, and then finds and executes the Bootstrap.php file inside each module. Since it iterates over directories, any Phar file we put there is just ignored. We will have to make sure that Phar files also get bootstrapped. We can do this by providing our own modules resource. The built-in one is called Zend_Application_Resource_Modules, and resides in Zend/Application/Resource/Modules.php. We don’t have to start hacking that file to add Phar support. We can create our own Modules.php resource, which extends the Zend Framework one. By providing our own implementation of an existing resource, we can add extra functionality on top of the existing code, without having to hack the existing code.

Here’s my implementation:

// file: library/MyLib/Application/Resource/Modules.php
class MyLib_Application_Resource_Modules extends Zend_Application_Resource_Modules
{
    /**
     * Initialize modules
     *
     * @return array
     */
    public function init()
    {
		// call parent functionality:
		parent::init();
		
		// find out module directory:
        $bootstrap = $this->getBootstrap();
        $bootstrap->bootstrap('FrontController');
        $front = $bootstrap->getResource('FrontController');
		$modulesDirectory = $front->getModuleDirectory() . '/modules'; // TODO hard coded...
		
        $default = $front->getDefaultModule();
        $curBootstrapClass = get_class($bootstrap);

		// find all PHAR modules, and bootstrap those:	
		$iterator = new DirectoryIterator($modulesDirectory);
		
		foreach ($iterator as $file) {
			if (!$file->isDot() && strpos($file->getFilename(), '.phar') > 0) {
				$module = str_replace('.phar', '', $file->getFilename());
				
				// bootstrap the module:
				$this->_bootstrapPharModule($file, $bootstrap, $default, $curBootstrapClass);
				
				// add to the modules in the FC
				$front->addControllerDirectory('phar://' . 
						$file->getPath() . 
						DIRECTORY_SEPARATOR . 
						$file->getFilename() . 
						DIRECTORY_SEPARATOR . 
						'controllers', 
				$module);
			}
		}
		
		return $this->_bootstraps;
    }
	
	/**
	 * Bootstraps a single PHAR module
	 *
	 * @param DirectoryIterator $file
	 * @param Zend_Application_Bootstrap $bootstrap
	 * @param string $default
	 * @param string $curBootstrapClass
	 * @return void
	 * @throws Zend_Application_Resource_Exception When bootstrap class was not found
	 */
	protected function _bootstrapPharModule (DirectoryIterator $file, $bootstrap, $default, $curBootstrapClass)
	{
		$fullPharPath = $file->getPath() . DIRECTORY_SEPARATOR . $file->getFilename();
		include($fullPharPath);
		$module = str_replace('.phar', '', $file->getFilename());
		
		$bootstrapClass = $this->_formatModuleName($module) . '_Bootstrap';
		if (!class_exists($bootstrapClass, false)) {
			$bootstrapPath  = 'phar://' . $fullPharPath . '/Bootstrap.php';
			if (file_exists($bootstrapPath)) {
				$eMsgTpl = 'Bootstrap file found for module "%s" but bootstrap class "%s" not found';
				include_once $bootstrapPath;
				if (($default != $module)
					&& !class_exists($bootstrapClass, false)
				) {
					throw new Zend_Application_Resource_Exception(sprintf(
						$eMsgTpl, $module, $bootstrapClass
					));
				} elseif ($default == $module) {
					if (!class_exists($bootstrapClass, false)) {
						$bootstrapClass = 'Bootstrap';
						if (!class_exists($bootstrapClass, false)) {
							throw new Zend_Application_Resource_Exception(sprintf(
								$eMsgTpl, $module, $bootstrapClass
							));
						}
					}
				}
			} else {
				// nothing to bootstrap, so let's move on
				return;
			}
		}
		
		if ($bootstrapClass == $curBootstrapClass) {
			// If the found bootstrap class matches the one calling this
			// resource, don't re-execute.
			return;
		}

		$moduleBootstrap = new $bootstrapClass($bootstrap);
		$moduleBootstrap->bootstrap();
		$this->_bootstraps[$module] = $moduleBootstrap;
	}
}

What happens is not very difficult: we find each Phar module, find the Bootstrap.php file in it, execute it and let the FrontController know we have bootstrapped a new module. The actual reading from a Phar file is handled transparently by the Phar module, and doesn’t need any special treatment in Zend Framework. Credits for this code should actually go to the Zend Framework: I looked into the original file, and almost literally copied what I could reuse.

Conclusion

Adding Phar support isn’t very hard. Too bad it isn’t built-in the framework, but luckily for us, the framework is flexible enough so we can add it. Once the module is bootstrapped, all classes can be used in your application. Once the FrontController knows where to locate your module, it’s accessible through the standard /module/controller/action request scheme. If you want to know more about creating your own Phar file, I recommend reading this excellent article from Cal Evans. It gave me exactly the information I needed for building my own Phar files.

How to let DomPDF and Zend Framework play along

For a recent project, I had to generate a PDF for a catalog. Since I’m using Zend Framework for my development, first thing that sprang in mind was Zend_Pdf. After some investigation, I found it too “difficult” to use. Flexible though that component is, I didn’t feel much for using coordinates to draw each and every line and text of that PDF. So I went to find another solution: DomPDF. DomPDF can generates PDF output, from HTML input. Exactly what I wanted and needed. It was however quite tricky to get it working. If you also have problems with this, read on!
read more »

Security with Zend_AMF and Flex – Part 2: Practise

In my previous post “Security with Zend_AMF and Flex – Part 1: Theory“, I explained the theory behind securing your Flex-PHP calls. After the theory comes the practise. I will only provide snippets for the PHP side of this story, as I’m totally ignorant about Flex and ActionScript. I used Zend_AMF, written by Wade Arnold, to handle all the communications between Flex and PHP. If you need to know the basics, please read the documentation first.
read more »

Security with Zend_AMF and Flex – Part 1: Theory

In a series of two posts, I will explain how to secure the communication between a Flex client and PHP server architecture. The first part will explain how I envision that security, and in the second part I will show snippets of PHP code for the practical implementation.

I’m currently working together with my friend and colleague Vic on a client-server application that involves Flex on the front-side, and PHP (Zend Framework) on the back. Since I’m the PHP guy, I’m in charge of creating the API for his Flex application. For the moment, the project will only be accessed locally from the client’s network. But there is a possibility that in a later stage, it might open up to the general public. One of my main concerns was how we could make every API call as secure as possible. This without making it too complicated, or involve too many service calls that might slow everything down.
read more »