PHP Developers Network
http://forums.devnetwork.net/

Zend Framework dependency manager
http://forums.devnetwork.net/viewtopic.php?f=50&t=123306
Page 1 of 1

Author:  Eran [ Mon Nov 01, 2010 10:31 am ]
Post subject:  Zend Framework dependency manager

I wrote a utility class for the Zend Framework that manages dependencies on the framework in application code. What it basically does is allow you to use ZF dependent code anywhere and the class will auto resolve dependencies and download them from the ZF SVN repository. You can also using it on existing ZF projects to get the minimally needed ZF library components, as it will only fetch what is being used in the project.

It works by prepending an autoload function to the autoload stack, interceptions calls to missing ZF classes and fetch them from the repository. If those classes have additional dependencies managed internally in the framework (helpers, plugins), it will fetch those dependencies as well. I've managed to build a working ZF library for several active projects I use using this class.

I'm looking for feedback on the code and missing dependencies if you encounter them.

The class - Zdm (Zend Framework Dependency Manager)
Syntax: [ Download ] [ Hide ]
<?php
/**
 * Zend Framework dependency manager
 *
 * Manages dependencies of the Zend Framework in application code.
 *
 * @category   Zdm
 * @copyright  Lionite Ltd.
 * @author     Eran Galperin
 * @license    http://www.opensource.org/licenses/mit-license.php  MIT license
 */

class Zdm {
        protected static $_instance = null;
        protected $_config = array(
                'libraryPath' => '/library', // If not passed will be set relative to Zdm class
                'prependStack' => true, // Prepend autoloader to autoload stack (otherwise append)
                'zfVersion' => '1.10.8', // Zend Framework version
                'repository' => 'http://framework.zend.com/svn/framework/standard/tags/release-'
        );

        protected $_dependencies = array(
                'Zend/Layout.php' => array('Zend/Filter/Word','Zend/Filter/StringToLower.php'),
                'Zend/View.php' => 'Zend/View',
                'Zend/Controller/Action.php' => 'Zend/Controller/Action/Helper'
        );

        /**
         * Initialize and register autoloader instance
         * @param array $config
         */

        public static function start($config = array()) {
                self::$_instance = new self($config);
        }

        /**
         * Get autoloader instance
         * @return Zdm
         */

        public static function getInstance() {
                if(is_null(self::$_instance)) {
                        self::$_instance = new self();
                }
                return self::$_instance;
        }

        /**
         * Constructor
         * @param array $config
         */

        protected function  __construct($config = array()) {
                $this -> _config = array_merge($this -> _config,$config);
                if(!isset($config['libraryPath'])) {
                        $this -> _config['libraryPath'] = dirname(__FILE__);
                }

                spl_autoload_register(get_class($this) . '::autoload',true,$this -> _config['prependStack']);
        }

        /**
         * Autoload function
         * @param string $class
         */

        public static function autoload($class) {
                if(!class_exists($class) && stripos($class,'Zend') !== false) {
                        $file = str_replace('_','/',$class) . '.php';
                        $self = self::getInstance();
                        $self -> load($file);
                }
        }

        /**
         * Require file - fetch from repository if does not exist
         * @param string $file
         */

        public function load($file) {
                $local = $this -> _config['libraryPath'] . DIRECTORY_SEPARATOR . $file;
                if(!is_file($local)) {
                        $this -> fetch($file);
                }
                require($local);
        }

        /**
         * Fetch Zend Framework class from repository
         * @param string $file ZF class file to fetch
         */

        public function fetch($file) {
                $local = $this -> _config['libraryPath'] . DIRECTORY_SEPARATOR . $file;
                $target = $this -> _config['repository'] . $this -> _config['zfVersion'] . '/library/' . $file;
                $data = file_get_contents($target);
                if(!is_dir(dirname($local))) {
                        mkdir(dirname($local),0755,true);
                }
                $offset = 0;
                while(($pos = strpos($data,"require_once",$offset)) !== false) {
                        $data = substr($data,0,$pos) . "//" . substr($data,$pos);
                        $offset = $pos + 10;
                }
                file_put_contents($local, $data);
                $this -> fetchDependencies($file);
        }

        /**
         * Fetch a directory of Zend Framework classes from repository
         * @param string $dir
         */

        public function fetchDir($dir) {
                $localDir = $this -> _config['libraryPath'] . DIRECTORY_SEPARATOR . $dir;
                if(!is_dir($localDir)) {
                        mkdir($localDir,0755,true);
                }
                $target = $this -> _config['repository'] . $this -> _config['zfVersion'] . '/library/' . $dir;

                //Local directory fetch
                if(is_dir($target)) {
                        foreach(glob($target . DIRECTORY_SEPARATOR . '*.*') as $file) {
                                $base = $dir . DIRECTORY_SEPARATOR . basename($file);
                                if(is_dir($file)) {
                                        $this -> fetchDir($base);
                                } else {
                                        $this -> fetch($base);
                                }
                        }
                //Zend Framework repo fetch
                } else {
                        $result = file_get_contents($target);
                        $tree = new DOMDocument();
                        $tree -> loadHTML($result);
                        $xpath = new DOMXPath($tree);
                        $result = $xpath -> query('//ul/li/a');
                        foreach($result as $node) {
                                $file = $node -> getAttribute('href');
                                if(strpos($file,'.php') === false) {
                                        if($file != '../') {
                                                $this -> fetchDir($dir .'/' . $file);
                                        }
                                } else {
                                        $this ->fetch($dir . '/' . $file);
                                }
                        }
                }
        }

        /**
         * Fetch dependencies for file
         * @param string $file
         */

        public function fetchDependencies($file) {
                if(array_key_exists($file, $this -> _dependencies)) {
                        $deps = (array)$this -> _dependencies[$file];
                        foreach($deps as $dep) {
                                if(stripos($dep,'.php') === false) {
                                        $this -> fetchDir($dep);
                                } else {
                                        $this -> fetch($dep);
                                }
                        }
                }
        }
}


Use instructions:
1. Include the class in your application (if it is a ZF application, it should be in the bootstrap)
2. Initialize the autoload by calling the static ::start() method
3. You can pass several optional parameters to the ::start() method -
* 'libraryPath' - the path that will store the ZF classes. Default is relative to the location of the Zdm class
* 'zfVersion' - version of the ZF to use
4. You would probably need to set the script time limit to 0 for the first run, as fetching the core of the library will take a while, depending on your connection.

Note: You need to remove 'require' and 'require_once' statements to ZF classes - those statements apply before the autoloader has a chance to catch the missing class and will result in a fatal error if the class is not present yet.

Example (in the beginning of the bootstrap):
Syntax: [ Download ] [ Hide ]
set_time_limit(0);
require_once('Zdm.php');
Zdm::start();

Author:  Eran [ Wed Nov 03, 2010 4:01 pm ]
Post subject:  Re: Zend Framework dependency manager

I'm wondering if anyone gave it a shot, and if so did it work as expected?

Author:  matthijs [ Tue Nov 30, 2010 2:32 am ]
Post subject:  Re: Zend Framework dependency manager

Looks interesting. Could be handy in case I want to use only a few parts of the ZF inside a website. I'll give it a try

Page 1 of 1 All times are UTC - 5 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/