PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Thu Oct 29, 2020 2:47 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Mon Nov 01, 2010 10:31 am 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
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();


Top
 Profile  
 
PostPosted: Wed Nov 03, 2010 4:01 pm 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
I'm wondering if anyone gave it a shot, and if so did it work as expected?


Top
 Profile  
 
PostPosted: Tue Nov 30, 2010 2:32 am 
Offline
DevNet Master

Joined: Thu Oct 06, 2005 3:57 pm
Posts: 3360
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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group