View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}
{composition-setup}
{zone-data:component-name}
Zend_Service_Twitter
{zone-data}

{zone-data:proposer-list}
[Matthew Weier O'Phinney|mailto:matthew@zend.com] and [Jon Whitcraft|mailto:jon.zf@mac.com]
{zone-data}

{zone-data:revision}
1.1 - 25 October 2007: Initial proposal creation
{zone-data}

{zone-data:overview}
Zend_Service_Twitter is a full implementation of the [Twitter API|http://apiwiki.twitter.com/].
{zone-data}

{zone-data:references}
* [Twitter API|http://apiwiki.twitter.com/]
{zone-data}

{zone-data:requirements}
* This component *will* implement the full Twitter API.
* This component *should* namespace the various API methods according to the groupings in the Twitter API documentation.
* This component *will* allow re-using an object with multiple user/pass combinations.
* This component *will* use a single format for all return values.
{zone-data}

{zone-data:dependencies}
* Zend_Rest_Client
* Zend_Service_Exception
{zone-data}

{zone-data:operation}
Zend_Service_Twitter will allow a developer to interact with the Twitter API, supporting such actions as updating status, retrieving status lists, sending and receiving direct messages, and creating and removing friendship status. To simplify operation, all methods are namespaced according to the various method groupings on the official API documentation.
{zone-data}

{zone-data:milestones}
* Milestone 1: \[DONE\] Design notes will be published here
* Milestone 2: Working prototype checked into the incubator supporting use cases
* Milestone 3: Unit tests exist, work, and are checked into SVN.
* Milestone 4: Initial documentation exists.
{zone-data}

{zone-data:class-list}
* Zend_Service_Twitter
* Zend_Service_Twitter_Search
* Zend_Service_TWitter_Exception
{zone-data}

{zone-data:use-cases}
||UC-01||
{code:php}
$twitter = new Zend_Service_Twitter($user, $pass);

// Get public timeline
$publicTimeline = $twitter->status->publicTimeline();

// Loop through results:
foreach ($publicTimeline->status as $status) {
$date = $status->created_at();
$text = $status->text();
$user = $status->user->screen_name();
echo "$date: @$user: $text<br />\n";
}

// Get friend timeline
$friendTimeline = $twitter->status->friendTimeline();

// Update status
$twitter->status->update("I'm writing Zend_Service_Twitter");

// Get followers
$followers = $twitter->user->followers();

// Send a direct message
$twitter->directMessage->new('zendcon07', 'Will you be at the conference?');

// Create a friendship
$twitter->friendship->create('zendcon07');
{code}

{zone-data}

{zone-data:skeletons}
{deck:id=Class Skeletons}
{card:label=Zend_Service_Twitter}
{code:php}
class Zend_Service_Twitter extends Zend_Rest_Client
{
/**
* Whether or not authorization has been initialized for the current user.
* @var bool
*/
protected $_authInitialized = false;

/**
* @var Zend_Http_CookieJar
*/
protected $_cookieJar;

/**
* Date format for 'since' strings
* @var string
*/
protected $_dateFormat = 'D, d M Y H:i:s e';

/**
* Username
* @var string
*/
protected $_username;

/**
* Password
* @var string
*/
protected $_password;

/**
* Current method type (for method proxying)
* @var string
*/
protected $_methodType;

/**
* Types of API methods
* @var array
*/
protected $_methodTypes = array(
'status',
'user',
'directMessage',
'friendship',
'account',
'favorite'
);

/**
* Constructor
*
* @param string $username
* @param string $password
* @return void
*/
public function __construct($username, $password)
{
$this->setUsername($username);
$this->setPassword($password);
$this->setUri('http://twitter.com');

$client = self::getHttpClient();
$client->setHeaders('Accept-Charset', 'ISO-8859-1,utf-8');
}

/**
* Retrieve username
*
* @return string
*/
public function getUsername()
{
return $this->_username;
}

/**
* Set username
*
* @param string $value
* @return Phly_Twitter
*/
public function setUsername($value)
{
$this->_username = $value;
$this->_authInitialized = false;
return $this;
}

/**
* Retrieve password
*
* @return string
*/
public function getPassword()
{
return $this->_password;
}

/**
* Set password
*
* @param string $value
* @return Phly_Twitter
*/
public function setPassword($value)
{
$this->_password = $value;
$this->_authInitialized = false;
return $this;
}

/**
* Proxy service methods
*
* @param string $type
* @return Phly_Twitter
* @throws Phly_Twitter_Exception if method is not in method types list
*/
public function __get($type)
{
if (!in_array($type, $this->_methodTypes)) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Invalid method type "' . $type . '"');
}

$this->_methodType = $type;
return $this;
}

/**
* Method overloading
*
* @param string $method
* @param array $params
* @return mixed
* @throws Phly_Twitter_Exception if unable to find method
*/
public function __call($method, $params)
{
if (empty($this->_methodType)) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Invalid method "' . $method . '"');
}

$test = $this->_methodType . ucfirst($method);
if (!method_exists($this, $test)) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Invalid method "' . $test . '"');
}

return call_user_func_array(array($this, $test), $params);
}

/**
* Initialize HTTP authentication
*
* @return void
*/
protected function _init()
{
$client = self::getHttpClient();

$client->resetParameters();

if (null == $this->_cookieJar) {
$client->setCookieJar();
$this->_cookieJar = $client->getCookieJar();
} else {
$client->setCookieJar($this->_cookieJar);
}

if (!$this->_authInitialized) {
$client->setAuth($this->getUsername(), $this->getPassword());
$this->_authInitialized = true;
}
}

/**
* Set date header
*
* @param int|string $value
* @return void
*/
protected function _setDate($value)
{
if (is_int($value)) {
$date = date($this->_dateFormat, $value);
} else {
$date = date($this->_dateFormat, strtotime($value));
}
self::getHttpClient()->setHeaders('If-Modified-Since', $date);
}

/**
* Public Timeline status
*
* @return Zend_Rest_Client_Result
*/
public function statusPublicTimeline()
{
$this->_init();
$path = '/statuses/public_timeline.xml';
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Friend Timeline Status
*
* $params may include one or more of the following keys
* - id: ID of a friend whose timeline you wish to receive
* - since: return results only after the date specified
* - page: return page X of results
*
* @param array $params
* @return void
*/
public function statusFriendsTimeline(array $params = array())
{
$this->_init();
$path = '/statuses/friends_timeline';
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'id':
$path .= '/' . $value;
break;
case 'since':
$this->_setDate($value);
break;
case 'page':
$this->page = (int) $value;
break;
default:
break;
}
}
$path .= '.xml';
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* User Timeline status
*
* $params may include one or more of the following keys
* - id: ID of a friend whose timeline you wish to receive
* - since: return results only after the date specified
* - page: return page X of results
* - count: how many statuses to return
*
* @return Zend_Rest_Client_Result
*/
public function statusUserTimeline(array $params = array())
{
$this->_init();
$path = '/statuses/user_timeline';
$_params = array();
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'id':
$path .= '/' . $value;
break;
case 'since':
$this->_setDate($value);
break;
case 'page':
$_params['page'] = (int) $value;
break;
case 'count':
$count = (int) $value;
if (0 >= $count) {
$count = 1;
} elseif (20 < $count) {
$count = 20;
}
$_params['count'] = $count;
break;
default:
break;
}
}
$path .= '.xml';
$response = $this->restGet($path, $_params);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Show a single status
*
* @param int $id Id of status to show
* @return Zend_Rest_Client_Result
*/
public function statusShow($id)
{
$this->_init();
$path = '/statuses/show/' . $id . '.xml';
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Update user's current status
*
* @param string $status
* @param int $in_reply_to_status_id
* @return Zend_Rest_Client_Result
* @throws Phly_Twitter_Exception if message is too short or too long
*/
public function statusUpdate($status, $in_reply_to_status_id = null)
{
$this->_init();
$path = '/statuses/update.xml';
$len = strlen($status);
if ($len > 140) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Status must be no more than 140 characters in length');
} elseif (0 == $len) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Status must contain at least one character');
}

$data = array(
'status' => $status
);

if(is_numeric($in_reply_to_status_id) && !empty($in_reply_to_status_id)) {
$this->in_reply_to_status_id = $in_reply_to_status_id;
}

//$this->status = $status;
$response = $this->restPost($path, $data);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Get status replies
*
* @param int $page Which page of replies to retrieve
* @return Zend_Rest_Client_Result
*/
public function statusReplies(array $params = array())
{
$this->_init();
$path = '/statuses/replies.xml';

$_params = array();
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'since':
$this->_setDate($value);
break;
case 'since_id':
$_params['since_id'] = (int) $value;
break;
case 'page':
$_params['page'] = (int) $value;
break;
default:
break;
}
}

$response = $this->restGet($path, $_params);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Destroy a status message
*
* @param int $id ID of status to destroy
* @return Zend_Rest_Client_Result
*/
public function statusDestroy($id)
{
$this->_init();
$path = '/statuses/destroy/' . (int) $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* User friends
*
* @param int|string $id Id or username of user for whom to fetch friends
* @return Zend_Rest_Client_Result
*/
public function userFriends($id = null)
{
$this->_init();
$path = '/statuses/friends';
if (null !== $id) {
$path .= '/' . $id;
}
$path .= '.xml';

$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* User Followers
*
* @param bool $lite If true, prevents inline inclusion of current status for followers; defaults to false
* @return Zend_Rest_Client_Result
*/
public function userFollowers($lite = false)
{
$this->_init();
$path = '/statuses/followers.xml';
if ($lite) {
$this->lite = 'true';
}

$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Get featured users
*
* @return Zend_Rest_Client_Result
*/
public function userFeatured()
{
$this->_init();
$path = '/statuses/featured.xml';

$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Show extended information on a user
*
* @param int|string $id User ID or name
* @return Zend_Rest_Client_Result
*/
public function userShow($id)
{
$this->_init();
$path = '/users/show/' . $id . '.xml';

$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Retrieve direct messages for the current user
*
* $params may include one or more of the following keys
* - since: return results only after the date specified
* - since_id: return statuses only greater than the one specified
* - page: return page X of results
*
* @param array $params
* @return Zend_Rest_Client_Result
*/
public function directMessageMessages(array $params = array())
{
$this->_init();
$path = '/direct_messages.xml';
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'since':
$this->_setDate($value);
break;
case 'since_id':
$this->since_id = (int) $value;
break;
case 'page':
$this->page = (int) $value;
break;
default:
break;
}
}
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Retrieve list of direct messages sent by current user
*
* $params may include one or more of the following keys
* - since: return results only after the date specified
* - since_id: return statuses only greater than the one specified
* - page: return page X of results
*
* @param array $params
* @return Zend_Rest_Client_Result
*/
public function directMessageSent(array $params = array())
{
$this->_init();
$path = '/direct_messages/sent.xml';
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'since':
$this->_setDate($value);
break;
case 'since_id':
$this->since_id = (int) $value;
break;
case 'page':
$this->page = (int) $value;
break;
default:
break;
}
}
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Send a direct message to a user
*
* @param int|string $user User to whom to send message
* @param string $text Message to send to user
* @return Zend_Rest_Client_Result
* @throws Phly_Twitter_Exception if message is too short or too long
*/
public function directMessageNew($user, $text)
{
$this->_init();
$path = '/direct_messages/new.xml';

$len = strlen($text);
if (0 == $len) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Direct message must contain at least one character');
} elseif (140 < $len) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Direct message must contain no more than 140 characters');
}

$data = array(
'user' => $user,
'text' => $text,
);

$response = $this->restPost($path, $data);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Destroy a direct message
*
* @param int $id ID of message to destroy
* @return Zend_Rest_Client_Result
*/
public function directMessageDestroy($id)
{
$this->_init();
$path = '/direct_messages/destroy/' . $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Create friendship
*
* @param int|string $id User ID or name of new friend
* @return Zend_Rest_Client_Result
*/
public function friendshipCreate($id)
{
$this->_init();
$path = '/friendships/create/' . $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Destroy friendship
*
* @param int|string $id User ID or name of friend to remove
* @return Zend_Rest_Client_Result
*/
public function friendshipDestroy($id)
{
$this->_init();
$path = '/friendships/destroy/' . $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Friendship exists
*
* @param int|string $id User ID or name of friend to see if they are your friend
* @return Zend_Rest_Client_result
*/
public function friendshipExists($id)
{
$this->_init();
$path = '/friendships/exists.xml';

$data = array(
'user_a' => $this->getUsername(),
'user_b' => $id
);

$response = $this->restGet($path, $data);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Verify Account Credentials
*
* @return Zend_Rest_Client_Result
*/
public function accountVerifyCredentials()
{
$this->_init();
$response = $this->restGet('/account/verify_credentials.xml');
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* End current session
*
* @return true
*/
public function accountEndSession()
{
$this->_init();
$response = $this->restGet('/account/end_session');
return true;
}

/**
* Returns the number of api requests you have left per hour.
*
* @return Zend_Rest_Client_Result
*/
public function accountRateLimitStatus()
{
$this->_init();
$response = $this->restGet('/account/rate_limit_status.xml');
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Fetch favorites
*
* $params may contain one or more of the following:
* - 'id': Id of a user for whom to fetch favorites
* - 'page': Retrieve a different page of resuls
*
* @param array $params
* @return Zend_Rest_Client_Result
*/
public function favoriteFavorites(array $params = array())
{
$this->_init();
$path = '/favorites';
foreach ($params as $key => $value) {
switch (strtolower($key)) {
case 'id':
$path .= '/' . $value;
break;
case 'page':
$this->page = (int) $value;
break;
default:
break;
}
}
$path .= '.xml';
$response = $this->restGet($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Mark a status as a favorite
*
* @param int $id Status ID you want to mark as a favorite
* @return Zend_Rest_Client_Result
*/
public function favoriteCreate($id)
{
$this->_init();
$path = '/favorites/create/' . (int) $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}

/**
* Remove a favorite
*
* @param int $id Status ID you want to de-list as a favorite
* @return Zend_Rest_Client_Result
*/
public function favoriteDestroy($id)
{
$this->_init();
$path = '/favorites/destroy/' . (int) $id . '.xml';

$response = $this->restPost($path);
return new Zend_Rest_Client_Result($response->getBody());
}
}
{code}
{card}
{card:label=Zend_Service_Twitter_Search}
{code:php}
class Zend_Service_Twitter_Search extends Zend_Http_Client
{
/**
* Return Type
* @var String
*/
protected $_responseType = 'json';

/**
* Response Format Types
* @var array
*/
protected $_responseTypes = array(
'atom',
'json'
);

/**
* Uri Compoent
*
* @var Zend_Uri_Http
*/
protected $_uri;

/**
* Constructor
*
* @param string $returnType
* @return void
*/
public function __construct($responseType = 'json')
{
$this->setResponseType($responseType);
$this->_uri = Zend_Uri_Http::fromString("http://search.twitter.com");

$this->setHeaders('Accept-Charset', 'ISO-8859-1,utf-8');
}

/**
* set responseType
*
* @param string $responseType
* @throws Phly_Twitter_Exception
* @return Phly_Twitter_Search
*/
public function setResponseType($responseType = 'json')
{
if(!in_array($responseType, $this->_responseTypes, TRUE)) {
include_once 'Phly/Twitter/Exception.php';
throw new Phly_Twitter_Exception('Invalid Response Type');
}
$this->_responseType = $responseType;
return $this;
}

/**
* Retrieve responseType
*
* @return string
*/
public function getResponseType()
{
return $this->_responseType;
}

/**
* Get the current twitter trends. Currnetly only supports json as the return.
*
* @return array
*/
public function trends()
{
$this->_uri->setPath('/trends.json');
$this->setUri($this->_uri);
$response = $this->request();

return Zend_Json::decode($response->getBody());
}

public function search($query, array $params = array())
{

$this->_uri->setPath('/search.' . $this->_responseType);
$this->_uri->setQuery(null);

$_query = array();

$_query['q'] = $query;

foreach($params as $key=>$param) {
switch($key) {
case 'geocode':
case 'lang':
$_query[$key] = $param;
break;
case 'rpp':
case 'since_id':
case 'page':
$_query[$key] = intval($param);
break;
case 'show_user':
$_query[$key] = 'true';
}
}

$this->_uri->setQuery($_query);

$this->setUri($this->_uri);
$response = $this->request();

switch($this->_responseType) {
case 'json':
return Zend_Json::decode($response->getBody());
break;
case 'atom':
return Zend_Feed::importString($response->getBody());
break;
}

return ;
}
}
{code}
{card}
{deck}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>