PageRenderTime 127ms CodeModel.GetById 81ms app.highlight 19ms RepoModel.GetById 21ms app.codeStats 0ms

/Service/Delicious.php

https://bitbucket.org/bigstylee/zend-framework
PHP | 616 lines | 272 code | 79 blank | 265 comment | 41 complexity | 9350d8f46fe54e45da03557021e476ea MD5 | raw file
  1<?php
  2
  3/**
  4 * Zend Framework
  5 *
  6 * LICENSE
  7 *
  8 * This source file is subject to the new BSD license that is bundled
  9 * with this package in the file LICENSE.txt.
 10 * It is also available through the world-wide-web at this URL:
 11 * http://framework.zend.com/license/new-bsd
 12 * If you did not receive a copy of the license and are unable to
 13 * obtain it through the world-wide-web, please send an email
 14 * to license@zend.com so we can send you a copy immediately.
 15 *
 16 * @category   Zend
 17 * @package    Zend_Service
 18 * @subpackage Delicious
 19 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 20 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 21 * @version    $Id: Delicious.php 24593 2012-01-05 20:35:02Z matthew $
 22 */
 23
 24
 25/**
 26 * @see Zend_Rest_Client
 27 */
 28require_once 'Zend/Rest/Client.php';
 29
 30/**
 31 * @see Zend_Json_Decoder
 32 */
 33require_once 'Zend/Json/Decoder.php';
 34
 35/**
 36 * @see Zend_Service_Delicious_SimplePost
 37 */
 38require_once 'Zend/Service/Delicious/SimplePost.php';
 39
 40/**
 41 * @see Zend_Service_Delicious_Post
 42 */
 43require_once 'Zend/Service/Delicious/Post.php';
 44
 45/**
 46 * @see Zend_Service_Delicious_PostList
 47 */
 48require_once 'Zend/Service/Delicious/PostList.php';
 49
 50
 51/**
 52 * Zend_Service_Delicious is a concrete implementation of the del.icio.us web service
 53 *
 54 * @category   Zend
 55 * @package    Zend_Service
 56 * @subpackage Delicious
 57 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 58 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 59 */
 60class Zend_Service_Delicious
 61{
 62    const API_URI = 'https://api.del.icio.us';
 63
 64    const PATH_UPDATE        = '/v1/posts/update';
 65    const PATH_TAGS          = '/v1/tags/get';
 66    const PATH_TAG_RENAME    = '/v1/tags/rename';
 67    const PATH_BUNDLES       = '/v1/tags/bundles/all';
 68    const PATH_BUNDLE_DELETE = '/v1/tags/bundles/delete';
 69    const PATH_BUNDLE_ADD    = '/v1/tags/bundles/set';
 70    const PATH_DATES         = '/v1/posts/dates';
 71    const PATH_POST_DELETE   = '/v1/posts/delete';
 72    const PATH_POSTS_GET     = '/v1/posts/get';
 73    const PATH_POSTS_ALL     = '/v1/posts/all';
 74    const PATH_POSTS_ADD     = '/v1/posts/add';
 75    const PATH_POSTS_RECENT  = '/v1/posts/recent';
 76
 77    const JSON_URI     = 'http://del.icio.us';
 78    const JSON_POSTS   = '/feeds/json/%s/%s';
 79    const JSON_TAGS    = '/feeds/json/tags/%s';
 80    const JSON_NETWORK = '/feeds/json/network/%s';
 81    const JSON_FANS    = '/feeds/json/fans/%s';
 82    const JSON_URL     = '/feeds/json/url/data';
 83
 84    /**
 85     * Zend_Service_Rest instance
 86     *
 87     * @var Zend_Service_Rest
 88     */
 89    protected $_rest;
 90
 91    /**
 92     * Username
 93     *
 94     * @var string
 95     */
 96    protected $_authUname;
 97
 98    /**
 99     * Password
100     *
101     * @var string
102     */
103    protected $_authPass;
104
105    /**
106     * Microtime of last request
107     *
108     * @var float
109     */
110    protected static $_lastRequestTime = 0;
111
112    /**
113     * Constructs a new del.icio.us Web Services Client
114     *
115     * @param  string $uname Client username
116     * @param  string $pass  Client password
117     * @return void
118     */
119    public function __construct($uname = null, $pass = null)
120    {
121        $this->_rest = new Zend_Rest_Client();
122        $this->_rest->getHttpClient()->setConfig(array('ssltransport' => 'ssl'));
123        $this->setAuth($uname, $pass);
124    }
125
126    /**
127     * Set client username and password
128     *
129     * @param  string $uname Client user name
130     * @param  string $pass  Client password
131     * @return Zend_Service_Delicious Provides a fluent interface
132     */
133    public function setAuth($uname, $pass)
134    {
135        $this->_authUname = $uname;
136        $this->_authPass  = $pass;
137
138        return $this;
139    }
140
141    /**
142     * Get time of the last update
143     *
144     * @throws Zend_Service_Delicious_Exception
145     * @return Zend_Date
146     */
147    public function getLastUpdate()
148    {
149        $response = $this->makeRequest(self::PATH_UPDATE);
150
151        $rootNode = $response->documentElement;
152        if ($rootNode && $rootNode->nodeName == 'update') {
153            /**
154             * @todo replace strtotime() with Zend_Date equivalent
155             */
156            return new Zend_Date(strtotime($rootNode->getAttribute('time')));
157        } else {
158            /**
159             * @see Zend_Service_Delicious_Exception
160             */
161            require_once 'Zend/Service/Delicious/Exception.php';
162            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
163        }
164    }
165
166    /**
167     * Get all tags, returning an array with tags as keys and number of corresponding posts as values
168     *
169     * @return array list of tags
170     */
171    public function getTags()
172    {
173        $response = $this->makeRequest(self::PATH_TAGS);
174
175        return self::_xmlResponseToArray($response, 'tags', 'tag', 'tag', 'count');
176    }
177
178    /**
179     * Rename a tag
180     *
181     * @param  string $old Old tag name
182     * @param  string $new New tag name
183     * @return Zend_Service_Delicious Provides a fluent interface
184     */
185    public function renameTag($old, $new)
186    {
187        $response = $this->makeRequest(self::PATH_TAG_RENAME, array('old' => $old, 'new' => $new));
188
189        self::_evalXmlResult($response);
190
191        return $this;
192    }
193
194    /**
195     * Get all bundles, returning an array with bundles as keys and array of tags as values
196     *
197     * @return array list of bundles
198     */
199    public function getBundles()
200    {
201        $response = $this->makeRequest(self::PATH_BUNDLES);
202
203        $bundles = self::_xmlResponseToArray($response, 'bundles', 'bundle', 'name', 'tags');
204        foreach ($bundles as &$tags) {
205            $tags = explode(' ', $tags);
206        }
207        return $bundles;
208    }
209
210    /**
211     * Adds a new bundle
212     *
213     * @param  string $bundle Name of new bundle
214     * @param  array  $tags   Array of tags
215     * @return Zend_Service_Delicious Provides a fluent interface
216     */
217    public function addBundle($bundle, array $tags)
218    {
219        $tags = implode(' ', (array) $tags);
220        $response = $this->makeRequest(self::PATH_BUNDLE_ADD, array('bundle' => $bundle, 'tags' => $tags));
221
222        self::_evalXmlResult($response);
223
224        return $this;
225    }
226
227    /**
228     * Delete a bundle
229     *
230     * @param  string $bundle Name of bundle to be deleted
231     * @return Zend_Service_Delicious Provides a fluent interface
232     */
233    public function deleteBundle($bundle)
234    {
235        $response = $this->makeRequest(self::PATH_BUNDLE_DELETE, array('bundle' => $bundle));
236
237        self::_evalXmlResult($response);
238
239        return $this;
240    }
241
242    /**
243     * Delete a post
244     *
245     * @param  string $url URL of post to be deleted
246     * @return Zend_Service_Delicious Provides a fluent interface
247     */
248    public function deletePost($url)
249    {
250        $response = $this->makeRequest(self::PATH_POST_DELETE, array('url' => $url));
251
252        self::_evalXmlResult($response);
253
254        return $this;
255    }
256
257    /**
258     * Get number of posts by date
259     *
260     * Returns array where keys are dates and values are numbers of posts
261     *
262     * @param  string $tag Optional filtering by tag
263     * @return array list of dates
264     */
265    public function getDates($tag = null)
266    {
267        $parms = array();
268        if ($tag) {
269            $parms['tag'] = $tag;
270        }
271
272        $response = $this->makeRequest(self::PATH_DATES, $parms);
273
274        return self::_xmlResponseToArray($response, 'dates', 'date', 'date', 'count');
275    }
276
277    /**
278     * Get posts matching the arguments
279     *
280     * If no date or url is given, most recent date will be used
281     *
282     * @param  string    $tag Optional filtering by tag
283     * @param  Zend_Date $dt  Optional filtering by date
284     * @param  string    $url Optional filtering by url
285     * @throws Zend_Service_Delicious_Exception
286     * @return Zend_Service_Delicious_PostList
287     */
288    public function getPosts($tag = null, Zend_Date $dt = null, $url = null)
289    {
290        $parms = array();
291        if ($tag) {
292            $parms['tag'] = $tag;
293        }
294        if ($url) {
295            $parms['url'] = $url;
296        }
297        if ($dt) {
298            $parms['dt'] = $dt->get('Y-m-d\TH:i:s\Z');
299        }
300
301        $response = $this->makeRequest(self::PATH_POSTS_GET, $parms);
302
303        return $this->_parseXmlPostList($response);
304    }
305
306    /**
307     * Get all posts
308     *
309     * @param  string $tag Optional filtering by tag
310     * @return Zend_Service_Delicious_PostList
311     */
312    public function getAllPosts($tag = null)
313    {
314        $parms = array();
315        if ($tag) {
316            $parms['tag'] = $tag;
317        }
318
319        $response = $this->makeRequest(self::PATH_POSTS_ALL, $parms);
320
321        return $this->_parseXmlPostList($response);
322    }
323
324    /**
325     * Get recent posts
326     *
327     * @param  string $tag   Optional filtering by tag
328     * @param  string $count Maximum number of posts to be returned (default 15)
329     * @return Zend_Service_Delicious_PostList
330     */
331    public function getRecentPosts($tag = null, $count = 15)
332    {
333        $parms = array();
334        if ($tag) {
335            $parms['tag'] = $tag;
336        }
337        if ($count) {
338            $parms['count'] = $count;
339        }
340
341        $response = $this->makeRequest(self::PATH_POSTS_RECENT, $parms);
342
343        return $this->_parseXmlPostList($response);
344    }
345
346    /**
347     * Create new post
348     *
349     * @return Zend_Service_Delicious_Post
350     */
351    public function createNewPost($title, $url)
352    {
353        return new Zend_Service_Delicious_Post($this, array('title' => $title, 'url' => $url));
354    }
355
356    /**
357     * Get posts of a user
358     *
359     * @param  string $user  Owner of the posts
360     * @param  int    $count Number of posts (default 15, max. 100)
361     * @param  string $tag   Optional filtering by tag
362     * @return Zend_Service_Delicious_PostList
363     */
364    public function getUserPosts($user, $count = null, $tag = null)
365    {
366        $parms = array();
367        if ($count) {
368            $parms['count'] = $count;
369        }
370
371        $path = sprintf(self::JSON_POSTS, $user, $tag);
372        $res = $this->makeRequest($path, $parms, 'json');
373
374        return new Zend_Service_Delicious_PostList($this, $res);
375    }
376
377    /**
378     * Get tags of a user
379     *
380     * Returned array has tags as keys and number of posts as values
381     *
382     * @param  string $user    Owner of the posts
383     * @param  int    $atleast Include only tags for which there are at least ### number of posts
384     * @param  int    $count   Number of tags to get (default all)
385     * @param  string $sort    Order of returned tags ('alpha' || 'count')
386     * @return array
387     */
388    public function getUserTags($user, $atleast = null, $count = null, $sort = 'alpha')
389    {
390        $parms = array();
391        if ($atleast) {
392            $parms['atleast'] = $atleast;
393        }
394        if ($count) {
395            $parms['count'] = $count;
396        }
397        if ($sort) {
398            $parms['sort'] = $sort;
399        }
400
401        $path = sprintf(self::JSON_TAGS, $user);
402
403        return $this->makeRequest($path, $parms, 'json');
404    }
405
406    /**
407     * Get network of a user
408     *
409     * @param  string $user Owner of the network
410     * @return array
411     */
412    public function getUserNetwork($user)
413    {
414        $path = sprintf(self::JSON_NETWORK, $user);
415        return $this->makeRequest($path, array(), 'json');
416    }
417
418    /**
419     * Get fans of a user
420     *
421     * @param  string $user Owner of the fans
422     * @return array
423     */
424    public function getUserFans($user)
425    {
426        $path = sprintf(self::JSON_FANS, $user);
427        return $this->makeRequest($path, array(), 'json');
428    }
429
430    /**
431     * Get details on a particular bookmarked URL
432     *
433     * Returned array contains four elements:
434     *  - hash - md5 hash of URL
435     *  - top_tags - array of tags and their respective usage counts
436     *  - url - URL for which details were returned
437     *  - total_posts - number of users that have bookmarked URL
438     *
439     * If URL hasen't been bookmarked null is returned.
440     *
441     * @param  string $url URL for which to get details
442     * @return array
443     */
444    public function getUrlDetails($url)
445    {
446        $parms = array('hash' => md5($url));
447
448        $res = $this->makeRequest(self::JSON_URL, $parms, 'json');
449
450        if(isset($res[0])) {
451            return $res[0];
452        } else {
453            return null;
454        }
455    }
456
457    /**
458     * Handles all GET requests to a web service
459     *
460     * @param   string $path  Path
461     * @param   array  $parms Array of GET parameters
462     * @param   string $type  Type of a request ("xml"|"json")
463     * @return  mixed  decoded response from web service
464     * @throws  Zend_Service_Delicious_Exception
465     */
466    public function makeRequest($path, array $parms = array(), $type = 'xml')
467    {
468        // if previous request was made less then 1 sec ago
469        // wait until we can make a new request
470        $timeDiff = microtime(true) - self::$_lastRequestTime;
471        if ($timeDiff < 1) {
472            usleep((1 - $timeDiff) * 1000000);
473        }
474
475        $this->_rest->getHttpClient()->setAuth($this->_authUname, $this->_authPass);
476
477        switch ($type) {
478            case 'xml':
479                $this->_rest->setUri(self::API_URI);
480                break;
481            case 'json':
482                $parms['raw'] = true;
483                $this->_rest->setUri(self::JSON_URI);
484                break;
485            default:
486                /**
487                 * @see Zend_Service_Delicious_Exception
488                 */
489                require_once 'Zend/Service/Delicious/Exception.php';
490                throw new Zend_Service_Delicious_Exception('Unknown request type');
491        }
492
493        self::$_lastRequestTime = microtime(true);
494        $response = $this->_rest->restGet($path, $parms);
495
496        if (!$response->isSuccessful()) {
497            /**
498             * @see Zend_Service_Delicious_Exception
499             */
500            require_once 'Zend/Service/Delicious/Exception.php';
501            throw new Zend_Service_Delicious_Exception("Http client reported an error: '{$response->getMessage()}'");
502        }
503
504        $responseBody = $response->getBody();
505
506        switch ($type) {
507            case 'xml':
508                $dom = new DOMDocument() ;
509
510                if (!@$dom->loadXML($responseBody)) {
511                    /**
512                     * @see Zend_Service_Delicious_Exception
513                     */
514                    require_once 'Zend/Service/Delicious/Exception.php';
515                    throw new Zend_Service_Delicious_Exception('XML Error');
516                }
517
518                return $dom;
519            case 'json':
520                return Zend_Json_Decoder::decode($responseBody);
521        }
522    }
523
524    /**
525     * Transform XML string to array
526     *
527     * @param   DOMDocument $response
528     * @param   string      $root     Name of root tag
529     * @param   string      $child    Name of children tags
530     * @param   string      $attKey   Attribute of child tag to be used as a key
531     * @param   string      $attValue Attribute of child tag to be used as a value
532     * @return  array
533     * @throws  Zend_Service_Delicious_Exception
534     */
535    private static function _xmlResponseToArray(DOMDocument $response, $root, $child, $attKey, $attValue)
536    {
537        $rootNode = $response->documentElement;
538        $arrOut = array();
539
540        if ($rootNode->nodeName == $root) {
541            $childNodes = $rootNode->childNodes;
542
543            for ($i = 0; $i < $childNodes->length; $i++) {
544                $currentNode = $childNodes->item($i);
545                if ($currentNode->nodeName == $child) {
546                    $arrOut[$currentNode->getAttribute($attKey)] = $currentNode->getAttribute($attValue);
547                }
548            }
549        } else {
550            /**
551             * @see Zend_Service_Delicious_Exception
552             */
553            require_once 'Zend/Service/Delicious/Exception.php';
554            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
555        }
556
557        return $arrOut;
558    }
559
560    /**
561     * Constructs Zend_Service_Delicious_PostList from XML response
562     *
563     * @param   DOMDocument $response
564     * @return  Zend_Service_Delicious_PostList
565     * @throws  Zend_Service_Delicious_Exception
566     */
567    private function _parseXmlPostList(DOMDocument $response)
568    {
569        $rootNode = $response->documentElement;
570
571        if ($rootNode->nodeName == 'posts') {
572            return new Zend_Service_Delicious_PostList($this, $rootNode->childNodes);
573        } else {
574            /**
575             * @see Zend_Service_Delicious_Exception
576             */
577            require_once 'Zend/Service/Delicious/Exception.php';
578            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
579        }
580    }
581
582    /**
583     * Evaluates XML response
584     *
585     * @param   DOMDocument $response
586     * @return  void
587     * @throws  Zend_Service_Delicious_Exception
588     */
589    private static function _evalXmlResult(DOMDocument $response)
590    {
591        $rootNode = $response->documentElement;
592
593        if ($rootNode && $rootNode->nodeName == 'result') {
594
595            if ($rootNode->hasAttribute('code')) {
596                $strResponse = $rootNode->getAttribute('code');
597            } else {
598                $strResponse = $rootNode->nodeValue;
599            }
600
601            if ($strResponse != 'done' && $strResponse != 'ok') {
602                /**
603                 * @see Zend_Service_Delicious_Exception
604                 */
605                require_once 'Zend/Service/Delicious/Exception.php';
606                throw new Zend_Service_Delicious_Exception("del.icio.us web service: '{$strResponse}'");
607            }
608        } else {
609            /**
610             * @see Zend_Service_Delicious_Exception
611             */
612            require_once 'Zend/Service/Delicious/Exception.php';
613            throw new Zend_Service_Delicious_Exception('del.icio.us web service has returned something odd!');
614        }
615    }
616}