Zend_Service_Flickr: Improving performance

I recently was working on a Flickr integration used in a promotional microsite for a certain major client. Kohana php framework is my weapon of choice in this situation for caching and serving all types of json-based web services and it works great for that but I needed some type of third-party library to use for the actual Flickr part of things. I’ve used Zend a lot in the past and found their stuff works fairly well after a bit of tuning, so I decided on Zend_Service_Flickr and went to work. This post deals with some stuff I did to the tagSearch() call to make things more efficient. I am also assuming that if you are reading this you are familiar with Zend Framework and are comfortable with extending classes from it.

Basically the service is broken down into three main parts: the actual service class that builds, validates, and sends the queries; a ResultSet wrapper that takes in the XML returned by Flickr and parses it with DOMDocument and XPath; a Result wrapper that represents each node in the ResultSet – it acts as a VO class containing information about each photo returned from flickr.photos.search

What ends up happening is that the service makes a call to Flickr and passes the resulting XML into the ResultSet. ResultSet then loops through each node in it’s DOM tree and creates a new Result for each one. Then the Result VO makes a separate call to flickr.photos.getSizes for EACH IMAGE in the result set.

Making that many queries to the Flickr API (which is known to be slow anyway) just doesn’t fly in a production environment. Of course you cache all the results of the image sizes but even with that caching you are still doing WAY too many requests within too short of a time span for the API to keep up. Fortunately there is an easy fix for this.

currently in Zend_Service_Flickr_Result the offending part is this:

        foreach ($xpath->query('./@*', $image) as $property) {
            $this->{$property->name} = (string) $property->value;
        }

        $this->_flickr = $flickr;

        foreach ($this->_flickr->getImageDetails($this->id) as $k => $v) {
            $this->$k = $v;
        }

getImageDetails() is a call in Zend_Service_Flickr that makes the external query to photos.getSizes. The thing is: this call is completely unnecessary because at this point you already have all the information you need to create all the image size urls just from what photos.search returns.

What you can do is override and extend Zend_Service_Flickr_Result. Then replace the second foreach loop which calls getImageDetails (you still need the first foreach!). You can replace it with logic like this:

     foreach ($xpath->query('./@*', $image) as $property) {
           $this->{$property->name} = (string) $property->value;
     }
    $baseUri = "http://farm{$this->farm}.static.flickr.com/{$this->server}/{$this->id}_{$this->secret}";
    $baseClick = "http://www.flickr.com/photos/{$this->owner}/{$this->id}/sizes/";            
               
    $baseUri = "http://farm{$this->farm}.static.flickr.com/{$this->server}/{$this->id}_{$this->secret}";
    $baseClick = "http://www.flickr.com/photos/{$this->owner}/{$this->id}/sizes/";            
               
    $image['Square'] = array(
        'uri' => $baseUri . '_s.jpg',
        'clickUri' => $baseClick . 'sq/',
    );
    $image['Thumbnail'] = array(
        'uri' => $baseUri . '_t.jpg',
        'clickUri' => $baseClick . 't/',
    );
    $image['Small'] = array(
        'uri' => $baseUri . '_m.jpg',
        'clickUri' => $baseClick . 's/',
    );
    $image['Medium'] = array(
        'uri' => $baseUri . '.jpg',
        'clickUri' => $baseClick . 'm/',
    );
    $image['Large'] = array(
        'uri' => $baseUri . '_b.jpg',
        'clickUri' => $baseClick . 'l/',
    );

Now you have an array called $image which contains all of the image links (i.e. all of the information that flickr.photos.getSizes returns), without having to make an extra call.

To integrate this with Zend_Service_Flickr you will need to extend FlickrResultSet->current() so that it uses your new Result class like so:

    public function current()
    {
        return new  My_Service_Flickr_Result($this->_results->item($this->_currentIndex), $this->_flickr);
    }

And you will also have to override Zend_Service_Flickr->tagSearch() so that it will use your new ResultSet class instead of the default. Just change the last line of the function to

        return new My_Service_Flickr_ResultSet($dom, $this);

I know all that might look confusing but if you have used Zend Framework before you know that this is just how it goes :) Anyway, I hope you find this useful. Happy Flickr-ing!

Comments


Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*