CodeIgniter Forums

Full Version: Using Zend Framework components in CI
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2

El Forum

[eluser]JoostV[/eluser]
Hi all,

Fred Wu posted a good tutorial on using Zend Framework components in your CI app.

He created a library that you only need to load if you're going to use it. This means no overhead until you actually call the class (unlike the hook used by Daniel Vecchiato -who is greatly admired nonetheless- that sets your include_path whether you use ZF or not)

Zend Framework has component with great functionality, such as
- API classes for use with numerous web services such as Flickr, GData, Twitter, etc
- A great Caching class, that also does partial caching and function caching
- Session and Auth classes
- Feed parser class
- Etc.

A lot of these classes can be used stand-alone.

After you've copied ZF and created the Zend library class, here's an example controller zendtest.php that uses Zend_Service_Flickr and Zend_Cache

Code:
<?php if (!defined('BASEPATH')) {exit('No direct script access allowed');}

class Test extends Controller {

    function Test() {

        parent::Controller();

    }

    /**
     * Use of Zend_Service_Flickr and Zend_Cache and in Codeigniter.
     *
     * You need to get a Flickr API key before you can use the
     * Zend_Service_Flickr class!     *
     * Get it at http://www.flickr.com/services/api/keys/apply/
     */
    function zendcache()
    {

        // Load libraries
        // Don't forget to copy ZF and the Zend.php library first!
        $this->load->library('zend');
        $this->zend->load('Zend/Cache');
        $this->zend->load('Zend/Service/Flickr');

        // Set up Zend_Cache
        // In this example, we use a 600 second lifetime for cache, so 10 minutes
        $cache = Zend_Cache::factory(
            'Core',
            'File',
            array('lifetime' => 600, 'automatic_serialization' => true),
            array('cache_dir' => BASEPATH . 'cache')
        );
        
        ## REPLACE null WITH YOUR FLICKR API KEY! ##
        // Set the Flickr API key
        $flickr_api_key = null;

        // Create the output if the cache missed
        if (!$output = $cache->load(md5($this->uri->uri_string()))) {

            // Set up the Zend_Service_Flickr class
            $flickr = new Zend_Service_Flickr($flickr_api_key);

            // Set the search tag that we are going to search Flickr for
            $tag = 'pindakaas'; // deafult search
            if ($this->uri->segment(3)) {
                $tag = $this->uri->segment(3);
            }

            // Search Flickr for this tag
            $results = $flickr->tagSearch($tag);

            // Create feedback
            $output = '<h1>Add a tag in segment 3 of the URI</h1>';
            $output .= '<p>You searched Flickr for <em>' . $tag . '</em> (' . date('d-m-Y H:i:s') . ')</p>';
            $output .= '<p>' . $results->totalResultsAvailable . ' result(s) found</p>';

            // Show images if there are any
            if ($results->totalResultsAvailable > 0) {

                foreach ($results as $result)
                {
                    $output .= '<img >Small->uri . '" alt="' . $result->title . '" />' . ' ';
                }
            }

            // Cache key is an md5 hash of the complete URI, including ALL parameters
            $cache->save($output, md5($this->uri->uri_string()));
        }

        // Echo to screen (we should really do this in a view file, but hey...)
        echo $output;

    }

}

El Forum

[eluser]JoostV[/eluser]
[EDIT] The controller should not be named zendtest.php but test.php Smile

El Forum

[eluser]mihailt[/eluser]
probably a slightly change would improve it Smile
Code:
&lt;?php if (!defined('BASEPATH')) {exit('No direct script access allowed');}

/**
* Zend Framework Loader
*
* Put the 'Zend' folder (unpacked from the Zend Framework package, under 'Library')
* in CI installation's 'application/libraries' folder
* You can put it elsewhere but remember to alter the script accordingly
*
* Usage:
*   1) $this->load->library('zend', 'Zend/Package/Name');
*   or
*   2) $this->load->library('zend');
*      then $this->zend->load('Zend/Package/Name');
*
* * the second usage is useful for autoloading the Zend Framework library
* * Zend/Package/Name does not need the '.php' at the end
*/
class CI_Zend
{
    /**
     * Constructor
     *
     * @param    string $class class name
     */
    function __construct($class = NULL)
    {
        // include path for Zend Framework
        // alter it accordingly if you have put the 'Zend' folder elsewhere

        ini_set('include_path',
        ini_get('include_path'). PATH_SEPARATOR . BASEPATH . 'extensions/');
        require_once('Zend/Loader.php');
        

        if ($class)
        {
            Zend_Loader::loadClass($class);
            log_message('debug', "Zend Class $class Loaded");
        }
        else
        {
            log_message('debug', "Zend Class Initialized");
        }
    }

    /**
     * Zend Class Loader
     *
     * @param    string $class class name
     */

    function load($class)
    {
        Zend_Loader::loadClass($class);
        log_message('debug', "Zend Class $class Loaded");
    }
}

?&gt;

El Forum

[eluser]JoostV[/eluser]
Ah, you placed it in a folder 'extensions'. That's a better place, indeed. Thnx.

El Forum

[eluser]mihailt[/eluser]
the main improvement is usage of Zend_Loader class over direct require_once call.

El Forum

[eluser]Phil Sturgeon[/eluser]
I was looking into a way to make it use normal CI syntax, meaning the following would be possible:

Code:
$this->zend->load('flickr', array('API_KEY'));

But call_usr_func_array() just doesnt work with constructors :'(

Code:
// EPIC FAIL
class Test {
    
    function __construct() {
        echo "Params: ";
        print_r(func_get_args());
    }
    
}

call_user_func_array(array('Test', '__construct'), array('param1', 'param2'));

Anyone got a way round it? If we could get these classes called in the loader with all arguments passed as in my example we wouldn't need to call $flickr = new Zend_Service_Flickr($flickr_api_key); in our controllers.

Must admit I don't know much about Zend, but would learn a little more if it would get on better with my friend.

El Forum

[eluser]JoostV[/eluser]
How about if you define the parameters in your construct?
Code:
function __construct($classes = array()){

    if(count($classes) > 0) {
        foreach($classes as $class){
            // Load class
        }
    }

}

El Forum

[eluser]Randy Casburn[/eluser]
[quote author="pyromaniac" date="1229111863"]
But call_usr_func_array() just doesnt work with constructors :'(
...Anyone got a way round it?
[/quote]

This is true because the callback function is being used on an object. In order for you to call a user defined function (__construct() in this case) inside an object with a callback function, the method must be a static method. There are two ways to call the method. One requires the object to be instantiated first, prior to the callback function being invoked. Since the __construct() method is called during instantiation, that kinda shoots your design in the foot. The other requires the Class and method to be called statically.

First let's set up the Test class since it is exactly the same either way...

Code:
class Test {
    
    function __construct() {
    }

    static function set_parameters()
    {
        echo "Params: ";
        print_r(func_get_args());
    }
    
}

Here are the two ways to accomplish what you want to do:

With a static Class call to a static method:
Code:
call_user_func_array('Test', 'set_parameters', array('param1', 'param2'));

With a call to a static method of an instantiated class:
Code:
$oTest = new Test();
call_user_func_array(array($oTest, 'set_parameters'), array('param1', 'param2'));


I hope you find this helpful,

Randy

El Forum

[eluser]fredwu[/eluser]
[quote author="mihailt" date="1229107610"]the main improvement is usage of Zend_Loader class over direct require_once call.[/quote]

From the Zend Framework user guide:

Quote: Zend_Loader vs. require_once()

The Zend_Loader methods are best used if the filename you need to load is variable. For example, if it is based on a parameter from user input or method argument. If you are loading a file or a class whose name is constant, there is no benefit to using Zend_Loader over using traditional PHP functions such as require_once().

I think it really depends on the usage to justify it as an 'improvement'. Smile

El Forum

[eluser]Phil Sturgeon[/eluser]
You guys slightly missed the point but gave very good answers. The point is im trying to call the constructs of the Zend library files, so I obviously do not want to make and modifications to them.

That means I cannot call a different method, or modify the constructor. I tried both of those before realizing it would be no help, and as far as I know there is no way to do it in PHP. So, I'm not bothering! Confusedhut:
Pages: 1 2