Aug 6, 2008 8:29:13 PM
I've been wondering for a while how I could better communicate with Codecaine.co.za's readers when I publish new posts, or when someone comments on one. I've ruled out email updates as being too intrusive, and while I have implemented RSS feeds both at the post level and at the comment level, I find them to be too passive. Twitter, I've decided, provides an excellent middle ground.
The result
I always like to begin my posts with the end result, so first let's decide what we're out to achieve. The Twitter API is incredibly rich, so the question is, really, to what extent it is practical to integrate a blog with it. I've decided to begin by investigating how to set up a ZF blog to update its status when a) a post is published and b) a comment is made.
Cronning it up
Interacting with a 3rd-party API can often have a negative impact on page load times. For instance, if the Twitter service is down (something not unfamiliar to regular Twitter users) when a user makes a comment, then the page may never load, or may time out. An easy work-around, trading immediacy for reliability, is to create a flag for each post and comment to indicate whether or not it has been submitted to Twitter. A cron job can then pick up new posts and comments and submit at a scheduled interval.
For instance, consider the following two tables:
CREATE TABLE posts ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, body TEXT NOT NULL, submitted DATETIME NOT NULL, is_tweeted TINYINT(1) NOT NULL DEFAULT 0 ); CREATE TABLE comments ( id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, post_id INT(11) NOT NULL, body TEXT NOT NULL, submitted DATETIME NOT NULL, is_tweeted TINYINT(1) NOT NULL DEFAULT 0 );
When posts are published, or comments made, `is_tweeted` is automatically set to 0. All that remains is for a cron job to pick up items with `is_tweeted` = 0, and to update the blog's Twitter user's status with something applicable, e.g.:
codecaine_co_za: New post: "Integrating Twitter with your ZF blog" http://codecaine.co.za/posts/.../ codecaine_co_za: New comment: "I totally disagree with your method..." http://codecaine.co.za/posts/.../#comment-123
For those of you unfamiliar with Twitter, your status updates can be a maximum of 140 characters long, so post titles and comment bodies need to be truncated.
Tools of the trade
Getting the interaction between ZF and Twitter going is incredibly simple. All that's required is that the PHP curl extension be installed (apt-get install php5-curl on Ubuntu), and Arc90's Twitter library, distributed under a BSD license. Installing the library is simple -- just unzip it and move everything from the lib/ folder into your ZF include path. It offers a comprehensive set of methods to interact with the Twitter API, though we'll be using updateStatus() only.
Hello... Tworld?
Getting started with Arc90's library is as easy as blueberry pie:
<?php
$twitter = new Arc90_Service_Twitter('username', 'password');
$twitter->updateStatus('Hello Tworld');
That's it! That's all it takes to update your Twitter status and to communicate with all your followers. So let's extend this to our blog scenario. Consider the following models and script:
<?php
// Post.php
class Post extends Zend_Db_Table_Abstract
{
protected $_name = 'posts';
public function getTweetText(Zend_Db_Table_Row $row)
{
$text = 'New post: "';
$url = '" http://codecaine.co.za/posts/' . $row->label;
$availableChars = 140 - strlen($url) - strlen($text) - 3; // -3 for ...
$length = strlen($row->title);
$text .= substr($row->title, 0, $availableChars) .
($length > $availableChars ? '...' : '');
$text .= $url;
return $text;
}
}
// Comment
class Comment extends Zend_Db_Table_Abstract
{
protected $_name = 'comments';
protected $_referenceMap = array(
'Post' => array(
'columns' => 'post_id',
'refTableClass' => 'Post',
'refColumns' => 'id'
)
);
public function getTweetText(Zend_Db_Table_Row $row)
{
$text = 'New comment: "';
$url = '" http://codecaine.co.za/posts/' .
$row->findParentRow('Post')->label .
'#comment-' . $row->id;
$availableChars = 140 - strlen($url) - strlen($text) - 3; // -3 for ...
$length = strlen($row->body);
$text .= substr($row->title, 0, $availableChars) .
($length > $availableChars ? '...' : '');
$text .= $url;
return $text;
}
}
// submitTweets.php
set_include_path(
get_include_path() . PATH_SEPARATOR .
'/path/to/library/folder/' . PATH_SEPARATOR .
'/path/to/models/fodler'
);
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoLoad();
$twitter = new Arc90_ServiceTwitter(
'username', 'password'
);
$postManager = new Post();
$posts = $postManager->fetchAll(
array('is_tweeted = ?' => 0),
'submitted'
);
foreach ($posts as $post)
{
$twitter->updateStatus(
$postManager->getTweetText($post)
);
$postManager->update(
array('is_tweeted' => 1),
array('id = ?' => $post->id)
);
}
// ... and something similar for comments
All that's happening is that posts/comments with is_tweeted = 0 are being picked up, tweeted, and then updated to is_tweeted = 1.
API restrictions
As a Twitter user, you are allowed 70 API requests per hour. For many blogs, +-1 tweet per minute will be sufficient to cover all comments and postings, but you may run into hassles if you get more than one comment per minute. There isn't really any way to overcome this (apart from being whitelisted), but you can certainly make sure that your tweeting doesn't get backed up, and that readers don't get stale comments.
The quickest way to do this is to add a threshold to the fetchAll() in submitTweets.php:
<?php
//...
$postManager = new Post();
$threshold = date(
'Y-m-d H:i:s', strtotime('-5 min')
);
$posts = $postManager->fetchAll(
array(
'is_tweeted = ?' => 0,
'submitted > ?' => $threshold
),
'submitted'
);
//...
In this way, users will get tweets that are at a maximum 5 minutes old, though when there's high traffic some comments/blog posts may get skipped.
Where to from here?
I'd really love to know what you think about interacting with a blog through Twitter. There is alway the possibility of expanding this code to allow you to make comments by direct messaging the blog Twitter user, or by receiving direct messages when your Twitter username is mentioned in a comment. Even though the restrictions on Twitter interactions are quite heavy, I feel that integration with Twitter could provide a far more immediate, personal and rich interaction with traditional blogging engines.
Discussion
Subscribe to an RSS feed of these commentsAubrey Kilian
Aug 7, 2008 7:05:32 AM
Look at how Wordpress does interactions with 3rd party websites. I think they have some sort of webbug or something that does an internal POST to Wordpress itself, which then fires off the talking to 3rd party sites, meaning there's not effect on the page loads.Also, using cron is limited to tech-heads, which I suppose is where ZF is also limited to I suppose. Most people won't have access to cron, so you'd need some other way of ensuring tweets get sent.
Neil Garb
Aug 8, 2008 6:38:38 AM
@Aubrey: Thanks -- will look at the WP code.You make a valid point about crons, but I leave that up to the individual reader. At the very least, you could do it synchronously with a timeout. PHP's curl API has a timeout option.
Luke
Aug 11, 2008 10:55:16 AM
Hey Neil, Feedburner has a handy option for non-RSS users to get your feed updates as emails.Like the idea of interacting with a comment thread via Twitter.. just not sure about the 140 char limit.. Anyhow, if your idea took off it could be a real death-blow to Twitter up-time..
Neil Garb
Aug 11, 2008 3:30:29 PM
@Luke: it's my mission to build as much of this blog on my own using ZF, both as practice for me and as a guide for people starting with ZF. Thanks for the suggestion though.Re: twitter falling over. Maybe the answer is to use an IM interface? Twitter is just a more natural choice because of its accessible API.
Your comment