With the web being what it is today there can be a lot of times when you want to aggregate data from many different sources and bring them together in a single page. I have not done much of that on my site simply because that means that I then need to learn a bunch of different API's. However, since Youtube is the #2 search engine I figured that it might not be a bad idea to aggregate some of my YouTube content on my page automatically. I don't necessarily want to do a blog post about each individual video I post, but I wanted there to be some place where I could just list them out.
I have two places where I post content. Youtube and Facebook. However, polling each site individually for each request is not conducive to having a page that renders quickly. The thing you do NOT want to do is poll YouTube each time someone comes to an individual page. The way around this is to cache the contents of the YouTube or Facebook query so you don't have to do that. Then people are able to re-use the previously defined data when they view that page. What this does is make most of the new requests to that page much faster since they don't have to re-load that data from YouTube or Facebook. However, there's a bit of a problem there as well. Every X number of minutes, the cache will expire and someone will take the hit of connecting to Youtube. With a moderately low traffic site such as mine, that hit is something I didn't want to make my users endure when they came to the site since there is a decent probability that the cache will expire in between individual page requests. And, working for Zend, I can't have a page that renders slowly, can I.
So what I did was create a new Zend Server Job Queue task, which I have detailed several times (and there should be a link to several on the side) that would connect to both YouTube and Facebook. This task would insert the results into a cache (you could use a database if you liked) so that when someone came to a page that they would be seeing the cached data rather than polling YouTube. From a settings perpective, the cache is set to never expire the content there. But because I set the task to run once an hour the content is going to be refreshed. Using this pre-population method I am able to keep requests snappy which at the same time providing mostly up to date content.
The task to do this is relatively simple. First I edit my application.ini file to set up the cache manager.
resources.cachemanager.video.frontend.name = Core
resources.cachemanager.video.frontend.options.automatic_serialization = true
resources.cachemanager.video.frontend.options.lifetime = null
resources.cachemanager.video.backend.name = File
By defining these ini settings, Zend_Application will automatically instantiate an instance of Zend_Cache_Manager and set up a cache that is named "video" with the individual options as specified. What this means is that I could create another cache interface by taking these configuration lines and giving it its own configuration settings. It could be different settings or even a completely different backend, or a different front end.
Then I create my task class.
class Admin_Task_VideoPreCache extends Esc_Queue_TaskAbstract
{
protected function _execute(Zend_Application $app)
{
$yt = new Zend_Gdata_YouTube();
$options = $app->getOption('video');
$uploads = $yt->getUserUploads($options['youtube']['id']);
$manager = $app->getBootstrap()->getResource('cachemanager');
/* @var $manager Zend_Cache_Manager */
$manager->getCache('video')->save($uploads, 'youtube');
$query = 'SELECT title, description, embed_html FROM video WHERE owner=' . $options['facebook']['id'];
$url = 'https://api.facebook.com/method/fql.query?query='.urlencode($query);
$data = simplexml_load_string(file_get_contents($url));
$videos = array();
foreach ($data->video as $video) {
$videos[] = array(
'title' => (string)$video->title,
'description' => (string)$video->description,
'embed_html' => (string)$video->embed_html
);
}
$manager->getCache('video')->save($videos, 'facebook');
}
}
Because the Zend_Application instance is always passed in I can easily get access to the predefined cache manager object in here for when I need to store the data at the end of the task. Then in the task I use Zend_GData_Youtube to query YouTube and I do a simple FQL query to Facebook to get the Facebook videos (which stopped working between test, staging and production. Go figure).
The next thing I have to do is make that data available to a view. To do that I need to create a new controller action that queries the cache manager.
public function myvideosAction()
{
$app = $this->getInvokeArg('bootstrap')->getApplication();
/* @var $app Zend_Application */
$cm = $app->getBootstrap()->getResource('cachemanager');
/* @var $cm Zend_Cache_Manager */
$this->view->youtube = $cm->getCache('video')->load('youtube');
$this->view->facebook = $cm->getCache('video')->load('facebook');
}
Then all I need to do in my view is iterate over the data and I'm pretty much good to go. Because the cache data has been prepopulated my visitors should never have to take the hit of populating the cache and by using the Zend Server Job Queue the task of populating the cache is extremely easy to do.
