CakePHP Twitter and Bitly Components

I promised more programming related posts, and here’s one for you.

As part of developing TweeterDiet.com, I needed to interface with Twitter and Bit.ly to post tweets and the links back to the public profiles on TweeterDiet. I searched around for a while, and didn’t immediately run across any good components for what I needed, so I wrote my own, and now I’d like to share them.

Up first, the Twitter Component. This relies on the EpiTwitter class from the twitter-async project on GitHub.

app/controllers/components/twitter.php:

class TwitterComponent extends Object {
	function __construct() {
		require_once(APP.'vendors/twitter-async/EpiCurl.php');
		require_once(APP.'vendors/twitter-async/EpiOAuth.php');
		require_once(APP.'vendors/twitter-async/EpiTwitter.php');
 
		$this->twitterObj = new EpiTwitter(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET);
 
		App::Import('Component', 'Bitly');
		$this->Bitly = new BitlyComponent();
	}
 
	function sendTweet($text, $url = null) {
		if ($url !== null) {
			$url = ' '.$this->Bitly->shorten($url);
		}
 
		$message = trim($text . $url);
 
		if (strlen($message) > 140) {
			return false;
		} else {
			try {
				$this->twitterObj->post_statusesUpdate(array('status' => $message));
			} catch (Exception $e) {
				return false;
			}
 
			return true;
		}
	}
 
	function __call($name, $arguments) {
		return call_user_func_array(array($this->twitterObj, $name), $arguments);
	}
}

This class expects you to define your app’s Twitter oAuth Consumer Key and Consumer Secret as constants. Here’s an example of how to do it:

app/config/bootstrap.php:

define('TWITTER_CONSUMER_KEY', 'KEY_HERE');
define('TWITTER_CONSUMER_SECRET', 'SECRET_HERE');

The Twitter component also relies on the Bit.ly component I wrote along with it, for doing URL shortening. Here’s the source code for it:

app/controllers/components/bitly.php:

class BitlyComponent extends Object {
	var $user;
	var $api_key;
 
	function __construct() {
		$this->user = BITLY_USER;
		$this->api_key = BITLY_API_KEY;
		$this->BitlyLink = ClassRegistry::init('BitlyLink');
	}
 
	function setApiInfo($user, $api_key) {
		$this->user = $user;
		$this->api_key = $api_key;
	}
 
	function shorten($long_url) {
		$cache = $this->BitlyLink->find('first', array('conditions' => array('BitlyLink.long_url' => $long_url)));
 
		if (!empty($cache['BitlyLink']['id'])) {
			return 'http://bit.ly/'.$cache['BitlyLink']['hash'];
		}
 
		$params = array();
 
		$params['login'] = $this->user;
		$params['apiKey'] = $this->api_key;
		$params['version'] = '2.0.1';
		$params['format'] = 'json';
		$params['longUrl'] = $long_url;
 
		$url = 'http://api.bit.ly/shorten?'.http_build_query($params);
 
		$ch = curl_init();
 
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
		$data = curl_exec($ch);
		curl_close($ch);
 
		$data = json_decode($data, true);
 
		if ($data['errorCode'] == 0) {
			$result = array_pop(array_values($data['results']));
 
			$save = array('BitlyLink' => array());
			$save['BitlyLink']['long_url'] = $long_url;
			$save['BitlyLink']['hash'] = $result['userHash'];
			$this->BitlyLink->create();
			$this->BitlyLink->save($save);
 
			return $result['shortUrl'];
		} else {
			return false;
		}
	}
}

This class expects two constants to be defined as well:

app/config/bootstrap.php

define('BITLY_USER', 'USER');
define('BITLY_API_KEY', 'API_KEY');

It also expects a model for caching the links so that it won’t have to send multiple requests for the same URL. Here’s the schema for that model:

BitlyLink Model:

CREATE TABLE IF NOT EXISTS `bitly_links` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `long_url` VARCHAR(255) NOT NULL,
  `hash` VARCHAR(255) NOT NULL,
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  PRIMARY KEY  (`id`),
  KEY `long_url` (`long_url`)
);

That about wraps it up. I use these two Components in TweeterDiet to help me with my communication to Twitter and Bitly. I hope they help someone else as well. If you have any questions, please post them below, and I’ll do what I can to help you.

%d bloggers like this: