Including An External Folder With Subfolders And Libraries

I want to use Elastica, a PHP client of ElasticSearch - a search engine somewhat similar to solr.

Now the installation guide of Elastica says to use autoload. But as far as I got it, the autoload features of yii work a little different. I anyway tried and created a symbolic link of the main folder Elastica in components and added to my main.php the line




			'import'=>array(

				'application.components.Elastica.*',

Now the guide says I can instantiate Elastica with $elasticaClient = new Elastica_Client(); which would call components/Elastica/Client.php because they included this nasty str_replace-feature in their autoload approach:


str_replace('_', '/', $class);

Well, Yii is obviously looking for Elastica_Client.php instead.

How would I do it right in a yii-way in order to be able to instantiate as mentioned and not touching the Elastica code or file structure?

The class filename should be exactly the same as the class name. That’s the Yii way. I think some renaming should fix your problem.

I will do that for now.

But since ElasticSearch as well as Elastica are in a fast development cycle and I would like to be able to simply pull the updates from GitHub - without renaming the 89 files each time - it doens’t seem to be the ideal solution.

Any other idea for the future?

You could write your own autoloader extension.

Take a look at EZendAutoloader extension - here’s a sample of how to register a custom autoloader with Yii (in index.php):





$app = Yii::createApplication('WebApplication', $config);


Yii::import('ext.EZendAutoloader', true);


EZendAutoloader::$prefixes = array('Zend');

EZendAutoloader::$basePath = Yii::getPathOfAlias('common.lib') . DIRECTORY_SEPARATOR;


Yii::registerAutoloader(array("EZendAutoloader", "loadClass"), true);


$app->run();



Thank you for your solution. To write my own autoloader extension is probably beyond my current level of knowledge of Yii as well as PHP but I will certainly keep it in mind for later.

I didn’t say that you should write your own from scratch. :)

Take a look at the Zend Autoloader Yii extension, and modify it.

Am I mistaken in assuming that the only thing you need to change to make it work is the word ‘Zend’ ?

Maybe something like this. It’s only an idea, not tested (don’t know anything about Elastica).

  1. Create Application component ‘ElasticaLoader.php’ in protected/components folder.




class ElasticaLoader extends CApplicationComponent

{

    public $libPath;


    //see: http://elastica.io/en#section-include

    public function __autoload_elastica ($class)

    {

        $path = str_replace('_', '/', $class);


        if (file_exists($this->libPath . $path . '.php')) {

            require_once($this->libPath . $path . '.php');

        }

    }




    public function init()

    {

       Yii::registerAutoloader(array($this,'__autoload_elastica'),true);

    }

}




  1. Preload the component in config/main.php




    ...

 

    'preload'=>array('log','importelastica'),


    ...


     'components'=>array(

        

      ...


        'importelastica'=>array( 

            'class' => 'application.components.ElasticaLoader',

            'libPath' => '/var/www/', //assume you installed Elastica to /var/www/Elastica

        ),


     ...




If you don’t need to ‘preload’ in the application, remove importelastica from ‘preload’ and call ‘Yii::app()->getComponent(‘importelastica’);’ in a controllers/modules init() or actionX method.

I am just starting, but it works splendid so far. All libraries seem to get loaded as wanted. Thanks a lot!

Dear Friend

The solution provided by joblo is indeed very elegant.

The question arises where to put that particular method for Yii::registerAutoloader.

Following is one approach.

I put the Elastica folder inside components folder.

Then I added the following.

protected/components/controller.php




class Controller extends CController

{

........................................................

public function autoloadElastica ($class)

    {

        $path = str_replace('_', '/', $class);


        if (file_exists(Yii::getPathOfAlias('application.components')."/". $path . '.php')) 

        {

            require_once(Yii::getPathOfAlias('application.components')."/". $path . '.php');

        }

    }


    public function init()

    {

       Yii::registerAutoloader(array($this,'autoloadElastica'),true);

    }

..............................................................



Regards.

For the record, the Zend Autoloader extension looks like this:





<?php

/**

 * EZendAutoloader

 *

 * @author Alexander Makarov

 * @version 1.1

 *

 * See readme for instructions.

 */

class EZendAutoloader {

	/**

     * @var array class prefixes

     */

	static $prefixes = array(

		'Zend'

	);


	/**

     * @var string path to where Zend classes root is located

     */

    static $basePath = null;


    /**

 	* Class autoload loader.

 	*

 	* @static

 	* @param string $class

 	* @return boolean

 	*/

    static function loadClass($className){

		foreach(self::$prefixes as $prefix){

			if(strpos($className, $prefix.'_')!==false){

				if(!self::$basePath) self::$basePath = Yii::getPathOfAlias("application.vendors").'/';

				include self::$basePath.str_replace('_','/',$className).'.php';

				return class_exists($className, false) || interface_exists($className, false);

			}

		}

		return false;

    }

}



Pretty much the same as Joblo’s solution. :)

Written by Samdark, from https://github.com/y...oader-component