├── .gitignore ├── .travis.yml ├── README.md ├── behat.yml.dist ├── composer.json ├── features ├── bootstrap │ └── FeatureContext.php └── remote.methods.feature ├── phpunit.xml.dist ├── src ├── Client.php ├── Plugin │ └── TokenAuthPlugin.php ├── Resources │ └── bitly.json └── Subscribers │ ├── ArrayAggregatorSubscriber.php │ └── ResponseStandardizationSubscriber.php └── tests └── ClientTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | vendor/* 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | env: 6 | global: 7 | - secure: "jLeBWhlYZqc5aXAxtUd+xn4SN4sTacqs/mrrX//QMLld3JnXAuweFI1rlJseI0n3sCjqQeDiHlKtwqdnIMO+iRssBkBUQJsjMOZZZn2RVGqyCh+/Xa4lSEp3uLTdog0EoRS8XA7GraSPC/kT1swANkgJhRI/EdwvpQdcpiFROdk=" 8 | 9 | php: 10 | - 7.0 11 | - 7.1 12 | - 7.2 13 | - 7.3 14 | - 7.4 15 | 16 | cache: 17 | directories: 18 | - $HOME/.composer/cache 19 | 20 | before_install: 21 | - composer config github-oauth.github.com $GITHUB_TOKEN 22 | 23 | install: 24 | - composer install --prefer-dist 25 | 26 | script: bin/phpunit 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BitlyApi 2 | 3 | ## This package is not maintained 4 | Check [phplicengine/bitly](https://packagist.org/packages/phplicengine/bitly) as a possible replacement. 5 | 6 | [![Build Status](https://travis-ci.org/hpatoio/bitly-api.svg?branch=master)](https://travis-ci.org/hpatoio/bitly-api) 7 | [![Total Downloads](https://poser.pugx.org/hpatoio/bitly-api/downloads.png)](https://packagist.org/packages/hpatoio/bitly-api) 8 | [![Latest Stable Version](https://poser.pugx.org/hpatoio/bitly-api/v/stable.png)](https://packagist.org/packages/hpatoio/bitly-api) 9 | [![SensioLabsInsight](https://insight.sensiolabs.com/projects/8d861d8b-3529-493d-b801-1a11a098492e/mini.png)](https://insight.sensiolabs.com/projects/8d861d8b-3529-493d-b801-1a11a098492e) 10 | 11 | PHP Library based on Guzzle to consume Bit.ly API. 12 | 13 | The biggest advantage in using Guzzle is that you can easely attach [Guzzle plugins](http://guzzle.readthedocs.org/en/latest/plugins/plugins-overview.html) to your client. [Here](#attach-guzzle-plugin), for example,you can see how to attach the log plugin and write all your requests to a file. 14 | 15 | An [integration](#integrations) with Symfony2 is available as well. 16 | 17 | ## Versions 18 | 19 | * branch `master` follows _psr4_ standards and get `2.x` tags 20 | * branch `psr0` follows, of course, _psr0_ standards and get `1.x` tags - No new features only bugfix 21 | 22 | This project follow [semantic versioning](http://semver.org/). 23 | 24 | ## Installation 25 | 26 | The recommended way to install this library is through Composer. 27 | For information about Composer and how to install in [look here](http://getcomposer.org/doc/00-intro.md). 28 | 29 | #### New project 30 | 31 | From the command line run 32 | 33 | ```shell 34 | ./composer create-project hpatoio/bitly-api your_prj_dir '~2.0' 35 | ``` 36 | 37 | #### Existing project 38 | 39 | Move into your project directory and run 40 | 41 | ```shell 42 | ./composer require hpatoio/bitly-api '~2.0' 43 | ``` 44 | or add to your `composer.json` 45 | ```json 46 | { 47 | ... 48 | "require": { 49 | ... 50 | "hpatoio/bitly-api": "~2.0" 51 | } 52 | } 53 | ``` 54 | and run 55 | ```shell 56 | ./composer update 57 | ``` 58 | 59 | ## Usage 60 | ```php 61 | Highvalue(array("limit" => 3)); 70 | 71 | print_r($response); 72 | 73 | ``` 74 | ## cURL options 75 | 76 | It might be that bit.ly is unreachable and you want to set a specific timeout. 77 | Just set the cURL timeout options in the client: 78 | 79 | ```php 80 | 81 | $my_bitly = new \Hpatoio\Bitly\Client("insert_here_your_bitly_api_access_token"); 82 | // set cURL timeout, you can specify any cURL options 83 | $my_bitly->setConfig(array( 84 | 'curl.options' => 85 | array( 86 | CURLOPT_TIMEOUT => 2, 87 | CURLOPT_CONNECTTIMEOUT => 2 88 | ) 89 | )); 90 | 91 | $response = $my_bitly->Highvalue(array("limit" => 3)); 92 | 93 | print_r($response); 94 | 95 | ``` 96 | 97 | 98 | ## Methods names 99 | 100 | To get the method name remove "v3" from the API url and camelize the other words removing the slashes. 101 | 102 | Examples: 103 | 104 | * /v3/highvalue -> Highvalue 105 | * /v3/realtime/hot_phrases -> RealtimeHot_phrases 106 | * /v3/link/content -> LinkContent 107 | 108 | ## Available methods 109 | At the moment the library supports these APIs: 110 | 111 | - [bitly Data APIs](http://dev.bitly.com/data_apis.html) 112 | - [Links](http://dev.bitly.com/links.html) 113 | - [Link Metrics](dev.bitly.com/link_metrics.html) 114 | - [User Metrics](http://dev.bitly.com/user_metrics.html) 115 | 116 | ## [Behat](http://behat.org) 117 | You need to copy Behat default configuration file and enter your ``access_token`` option there. 118 | ```bash 119 | $ cp behat.yml.dist behat.yml 120 | ``` 121 | Now open `behat.yml` and change the string `your_bitly_access_token_here` with your access token. 122 | Run the suite typing 123 | ```bash 124 | $ bin/behat 125 | ``` 126 | 127 | ## Integrations 128 | A Symfony2 bundle that integrate this library is available [here](https://github.com/hpatoio/BitlyBundle) 129 | 130 | ## Attach Guzzle plugin 131 | 132 | Here you can see how to attach Guzzle Log plug to your client and save all your requests to a file. 133 | 134 | *NB:* To run this script you need `monolog/monolog` 135 | 136 | ```php 137 | pushHandler(new StreamHandler('/tmp/bitly_guzzle.log')); 149 | $adapter = new MonologLogAdapter($logger); 150 | $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); 151 | 152 | # To find your bitly access token see here https://bitly.com/a/oauth_apps 153 | $my_bitly = new \Hpatoio\Bitly\Client("your_bitly_access_token"); 154 | $my_bitly->addSubscriber($logPlugin); 155 | 156 | $response = $my_bitly->Highvalue(array("limit" => 3)); 157 | 158 | print_r($response); 159 | ``` 160 | 161 | Now in `/tmp/bitly_guzzle.log` you can see all your requests. 162 | -------------------------------------------------------------------------------- /behat.yml.dist: -------------------------------------------------------------------------------- 1 | # This file is part of the bitly-client package. 2 | # (c) Simone Fumagalli 3 | 4 | default: 5 | context: 6 | parameters: 7 | access_token: you_bitly_access_token_here 8 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hpatoio/bitly-api", 3 | "type": "library", 4 | "description": "PHP Library based on Guzzle to consume Bit.ly API | This library is deprecated you might use https://github.com/phplicengine/bitly", 5 | "keywords": ["Bitly", "api", "guzzle", "behat"], 6 | "homepage": "http://www.iliveinperego.com/", 7 | "license": "CC-BY-SA-3.0", 8 | "authors": [ 9 | { 10 | "name": "Simone Fumagalli", 11 | "email": "simone@iliveinperego.com" 12 | } 13 | ], 14 | "require": { 15 | "guzzlehttp/guzzle": "~3.0" 16 | }, 17 | "require-dev": { 18 | "phpunit/phpunit": "~4.0", 19 | "behat/behat": "~2.0", 20 | "behat/mink": "~1.5" 21 | }, 22 | "config": { 23 | "bin-dir": "bin/" 24 | }, 25 | "suggest" : { 26 | "hpatoio/bitly-bundle" : "for integration with Symfony2 web framework", 27 | "phplicengine/bitly": "The package you have installed, hpatoio/bitly-api, is not maintained anymore. You might use https://github.com/phplicengine/bitly" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "Hpatoio\\Bitly\\": "src/" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /features/bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | context_parameters = $parameters; 24 | $this->request_parameters = array(); 25 | $this->client = new Hpatoio\Bitly\Client($parameters['access_token']); 26 | } 27 | 28 | /** 29 | * @Given /^the following parameters:$/ 30 | */ 31 | public function pushParams(TableNode $parametersTable) 32 | { 33 | foreach ($parametersTable->getHash() as $parameterHash) { 34 | if ($parameterHash['casting']) { 35 | if ($parameterHash['casting'] == 'Array') 36 | $parameterHash['value'] = explode(",",$parameterHash['value']); 37 | else 38 | settype($parameterHash['value'], $parameterHash['casting']); 39 | } 40 | $this->request_parameters[$parameterHash['name']] = $parameterHash['value']; 41 | } 42 | 43 | } 44 | 45 | /** 46 | * @When /^I request "([^"]*)"$/ 47 | */ 48 | public function iRequest($arg1) 49 | { 50 | $this->response = $this->client->$arg1($this->request_parameters); 51 | 52 | } 53 | 54 | /** 55 | * @Then /^the response has a "([^"]*)" key$/ 56 | */ 57 | public function theResponseHasKey($key) 58 | { 59 | $data = $this->response; 60 | 61 | if (!empty($data)) { 62 | if (!isset($data[$key] )) 63 | throw new Exception("Key '".$key."' is not set!\n"); 64 | } else { 65 | throw new Exception("Response was not JSON\n"); 66 | } 67 | 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /features/remote.methods.feature: -------------------------------------------------------------------------------- 1 | Feature: Test requests to Bitly API 2 | Scenario: Call Highvalue 3 | Given the following parameters: 4 | | name | value | casting | 5 | | limit | 3 | integer | 6 | When I request "Highvalue" 7 | Then the response has a "values" key 8 | Scenario: Call Search 9 | Given the following parameters: 10 | | name | value | casting | 11 | | limit | 3 | integer | 12 | | query | Simone | | 13 | When I request "Search" 14 | Then the response has a "results" key 15 | Scenario: Call RealtimeBursting_phrases 16 | When I request "RealtimeBursting_phrases" 17 | Then the response has a "phrases" key 18 | Then the response has a "current_lag" key 19 | Then the response has a "selectivity" key 20 | Then the response has a "time" key 21 | Scenario: Call RealtimeHot_phrases 22 | When I request "RealtimeHot_phrases" 23 | Then the response has a "phrases" key 24 | Then the response has a "lag" key 25 | Then the response has a "time" key 26 | Scenario: Call RealtimeClickrate 27 | Given the following parameters: 28 | | name | value | casting | 29 | | phrase | Pizza | | 30 | When I request "RealtimeClickrate" 31 | Then the response has a "lag" key 32 | Then the response has a "phrase" key 33 | Then the response has a "rate" key 34 | Then the response has a "time" key 35 | Scenario: Call LinkInfo 36 | Given the following parameters: 37 | | name | value | casting | 38 | | link | http://bit.ly/bitly_website | | 39 | When I request "LinkInfo" 40 | Then the response has a "canonical_url" key 41 | Then the response has a "category" key 42 | Scenario: Call LinkContent 43 | Given the following parameters: 44 | | name | value | casting | 45 | | link | http://bit.ly/bitly_website | | 46 | When I request "LinkContent" 47 | Then the response has a "content" key 48 | Then the response has a "content_type" key 49 | Scenario: Call LinkContent with content_type 50 | Given the following parameters: 51 | | name | value | casting | 52 | | link | http://bit.ly/bitly_website | | 53 | | content_type | text | | 54 | When I request "LinkContent" 55 | Then the response has a "content" key 56 | Then the response has a "content_type" key 57 | Scenario: Call LinkCategory 58 | Given the following parameters: 59 | | name | value | casting | 60 | | link | http://bit.ly/bitly_website | | 61 | When I request "LinkCategory" 62 | Then the response has a "categories" key 63 | Scenario: Call LinkSocial 64 | Given the following parameters: 65 | | name | value | casting | 66 | | link | http://bit.ly/bitly_website | | 67 | When I request "LinkSocial" 68 | Then the response has a "social_scores" key 69 | Scenario: Call LinkLocation 70 | Given the following parameters: 71 | | name | value | casting | 72 | | link | http://bit.ly/bitly_website | | 73 | When I request "LinkLocation" 74 | Then the response has a "locations" key 75 | Scenario: Call LinkLanguage 76 | Given the following parameters: 77 | | name | value | casting | 78 | | link | http://bit.ly/bitly_website | | 79 | When I request "LinkLanguage" 80 | Then the response has a "languages" key 81 | Scenario: Call Expand 82 | Given the following parameters: 83 | | name | value | casting | 84 | | shortUrl | http://bit.ly/bitly_website | | 85 | When I request "Expand" 86 | Then the response has a "expand" key 87 | Scenario: Call Expand with hash 88 | Given the following parameters: 89 | | name | value | casting | 90 | | hash | bitly_website | | 91 | When I request "Expand" 92 | Then the response has a "expand" key 93 | Scenario: Call Info 94 | Given the following parameters: 95 | | name | value | casting | 96 | | shortUrl | http://bit.ly/bitly_website | | 97 | When I request "Info" 98 | Then the response has a "info" key 99 | Scenario: Call Info with hash 100 | Given the following parameters: 101 | | name | value | casting | 102 | | hash | bitly_website | | 103 | When I request "Info" 104 | Then the response has a "info" key 105 | Scenario: Call expanded Info with hash 106 | Given the following parameters: 107 | | name | value | casting | 108 | | hash | bitly_website | | 109 | | expand | true | | 110 | When I request "Info" 111 | Then the response has a "info" key 112 | Scenario: Call link edit 113 | Given the following parameters: 114 | | name | value | casting | 115 | | link | http://bit.ly/11doabL | | 116 | | edit | note,note | array | 117 | | title | Set From Behat | | 118 | | note | Set From Behat | | 119 | When I request "UserLink_edit" 120 | Then the response has a "link_edit" key 121 | Scenario: Call lookup 122 | Given the following parameters: 123 | | name | value | casting | 124 | | url | http://www.iliveinperego.com | | 125 | When I request "UserLink_lookup" 126 | Then the response has a "link_lookup" key 127 | Scenario: Call shorten 128 | Given the following parameters: 129 | | name | value | casting | 130 | | longUrl | http://www.iliveinperego.com | | 131 | When I request "Shorten" 132 | Then the response has a "global_hash" key 133 | Then the response has a "hash" key 134 | Then the response has a "long_url" key 135 | Then the response has a "new_hash" key 136 | Then the response has a "url" key 137 | Scenario: Call link lookup 138 | Given the following parameters: 139 | | name | value | casting | 140 | | url | http://www.iliveinperego.com | | 141 | When I request "UserLink_lookup" 142 | Then the response has a "link_lookup" key 143 | Scenario: Call link save 144 | Given the following parameters: 145 | | name | value | casting | 146 | | longUrl | http://www.iliveinperego.com | | 147 | | title | Set From Behat 'link save' | | 148 | | note | Set From Behat 'link save' | | 149 | When I request "UserLink_save" 150 | Then the response has a "link_save" key 151 | Scenario: Call link clicks 152 | Given the following parameters: 153 | | name | value | casting | 154 | | link | http://bit.ly/bitly_website | | 155 | | unit | month | | 156 | | units | 2 | | 157 | | rollup | true | | 158 | | timezone | 0 | | 159 | When I request "LinkClicks" 160 | Then the response has a "link_clicks" key 161 | Scenario: Call link countries 162 | Given the following parameters: 163 | | name | value | casting | 164 | | link | http://bit.ly/bitly_website | | 165 | | unit | month | | 166 | | units | 2 | | 167 | When I request "LinkCountries" 168 | Then the response has a "countries" key 169 | Scenario: Call link encoders 170 | Given the following parameters: 171 | | name | value | casting | 172 | | link | http://bit.ly/bitly_website | | 173 | | limit | 20 | | 174 | When I request "LinkEncoders" 175 | Then the response has a "aggregate_link" key 176 | Scenario: Call link encoders by count 177 | Given the following parameters: 178 | | name | value | casting | 179 | | link | http://bit.ly/bitly_website | | 180 | | limit | 20 | | 181 | When I request "LinkEncoders_by_count" 182 | Then the response has a "aggregate_link" key 183 | Scenario: Call link encoders count 184 | Given the following parameters: 185 | | name | value | casting | 186 | | link | http://bit.ly/bitly_website | | 187 | When I request "LinkEncoders_count" 188 | Then the response has a "aggregate_link" key 189 | Scenario: Call link referrers 190 | Given the following parameters: 191 | | name | value | casting | 192 | | link | http://bit.ly/bitly_website | | 193 | When I request "LinkReferrers" 194 | Then the response has a "referrers" key 195 | Scenario: Call link referrers by domain 196 | Given the following parameters: 197 | | name | value | casting | 198 | | link | http://bit.ly/bitly_website | | 199 | When I request "LinkReferrers_by_domain" 200 | Then the response has a "referrers" key 201 | Scenario: Call link referring domain 202 | Given the following parameters: 203 | | name | value | casting | 204 | | link | http://bit.ly/bitly_website | | 205 | | unit | month | | 206 | | units | 1 | | 207 | When I request "LinkReferring_domains" 208 | Then the response has a "referring_domains" key 209 | Scenario: Call link shares 210 | Given the following parameters: 211 | | name | value | casting | 212 | | link | http://bit.ly/bitly_website | | 213 | | unit | month | | 214 | | units | 1 | | 215 | | rollup | true | | 216 | | timezone | 0 | | 217 | When I request "LinkShares" 218 | Then the response has a "shares" key -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests/ 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Client.php: -------------------------------------------------------------------------------- 1 | setDescription(ServiceDescription::factory(__DIR__.'/Resources/bitly.json')); 21 | 22 | $this->addSubscriber(new TokenAuthPlugin($access_token)); 23 | $this->addSubscriber(new ArrayAggregatorSubscriber()); 24 | $this->addSubscriber(new ResponseStandardizationSubscriber()); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/Plugin/TokenAuthPlugin.php: -------------------------------------------------------------------------------- 1 | token = $token; 21 | } 22 | 23 | public static function getSubscribedEvents() 24 | { 25 | return array('command.before_prepare' => array('onBeforePrepare', 255)); 26 | } 27 | 28 | /** 29 | * Add token 30 | * 31 | * @param Event $event 32 | */ 33 | public function onBeforePrepare(Event $event) 34 | { 35 | $event['command']->set('access_token', $this->token); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Resources/bitly.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hpatoio Bitly Client", 3 | "apiVersion": "1.0", 4 | "description": "Guzzle service description of Bitly API", 5 | "baseUrl": "https://api-ssl.bitly.com/", 6 | "operations": { 7 | "abstract.bitly": { 8 | "parameters": { 9 | "access_token": { 10 | "location": "query", 11 | "description": "Your Bitly access token", 12 | "required": true 13 | } 14 | } 15 | }, 16 | "abstract.bitly.link": { 17 | "extends" : "abstract.bitly", 18 | "parameters": { 19 | "link": { 20 | "location": "query", 21 | "type" : "string", 22 | "description": "A bitly link.", 23 | "required": true 24 | } 25 | } 26 | }, 27 | "Highvalue": { 28 | "extends" : "abstract.bitly", 29 | "httpMethod": "GET", 30 | "uri": "/v3/highvalue", 31 | "summary" : "Returns a specified number of \"high-value\" bitly links that are popular across bitly at this particular moment.", 32 | "parameters": { 33 | "limit": { 34 | "location": "query", 35 | "type" : "integer", 36 | "description": "The maximum number of high-value links to return.", 37 | "required": true 38 | } 39 | } 40 | }, 41 | "Search": { 42 | "extends" : "abstract.bitly", 43 | "httpMethod": "GET", 44 | "uri": "/v3/search", 45 | "summary" : "Search links receiving clicks across bitly by content, language, location, and more.", 46 | "parameters": { 47 | "limit": { 48 | "location": "query", 49 | "type" : "integer", 50 | "description": "The maximum number of links to return.", 51 | "required": false 52 | }, 53 | "offset": { 54 | "location": "query", 55 | "type" : "integer", 56 | "description": "Which result to start with (defaults to 0)", 57 | "required": false 58 | }, 59 | "query": { 60 | "location": "query", 61 | "type" : "string", 62 | "description": "String to query for", 63 | "required": false 64 | }, 65 | "lang": { 66 | "location": "query", 67 | "type" : "string", 68 | "description": "Favor results in this language (two letter ISO code).", 69 | "required": false 70 | }, 71 | "cities": { 72 | "location": "query", 73 | "type" : "string", 74 | "description": "Show links active in this city (ordered like country-state-city, e.g. us-il-chicago).", 75 | "required": false 76 | }, 77 | "domain": { 78 | "location": "query", 79 | "type" : "string", 80 | "description": "Restrict results to this web domain (like bitly.com).", 81 | "required": false 82 | }, 83 | "full_domain": { 84 | "location": "query", 85 | "type" : "string", 86 | "description": "Restrict results to this full web domain (like blog.bitly.com)", 87 | "required": false 88 | }, 89 | "fields": { 90 | "location": "query", 91 | "type" : "array", 92 | "description": "which fields to return in the response (comma-separated). May be any of: domain, initial_epoch, h2, h3, site, lastindexed, keywords, last_indexed_epoch, title, initial, summaryText, content, score, summaryTitle, type, description, cities, lang, url, referrer, aggregate_link, lastseen, page, ogtitle, aggregate_link. By default, all will be returned", 93 | "required": false 94 | } 95 | } 96 | }, 97 | "RealtimeBursting_phrases": { 98 | "extends" : "abstract.bitly", 99 | "httpMethod": "GET", 100 | "uri": "/v3/realtime/bursting_phrases", 101 | "summary" : "Returns phrases that are receiving an uncharacteristically high volume of click traffic, and the individual links (hashes) driving traffic to pages containing these phrases" 102 | }, 103 | "RealtimeHot_phrases": { 104 | "extends" : "abstract.bitly", 105 | "httpMethod": "GET", 106 | "uri": "/v3/realtime/hot_phrases", 107 | "summary" : "Returns phrases that are receiving a consistently high volume of click traffic, and the individual links (hashes) driving traffic to pages containing these phrases" 108 | }, 109 | "RealtimeClickrate": { 110 | "extends" : "abstract.bitly", 111 | "httpMethod": "GET", 112 | "uri": "/v3/realtime/clickrate", 113 | "summary" : "Returns the click rate for content containing a specified phrase", 114 | "parameters": { 115 | "phrase": { 116 | "location": "query", 117 | "type" : "string", 118 | "description": "The phrase for which you'd like to get the click rate", 119 | "required": true 120 | } 121 | } 122 | }, 123 | "LinkInfo": { 124 | "extends" : "abstract.bitly.link", 125 | "httpMethod": "GET", 126 | "uri": "/v3/link/info", 127 | "summary" : "Returns metadata about a single bitly link" 128 | }, 129 | "LinkContent": { 130 | "extends" : "abstract.bitly.link", 131 | "httpMethod": "GET", 132 | "uri": "/v3/link/content", 133 | "summary" : "Returns the “main article” from the linked page, as determined by the content extractor, in either HTML or plain text format", 134 | "parameters": { 135 | "content_type": { 136 | "location": "query", 137 | "enum": ["html", "text"], 138 | "description": "specifies whether to return the content as html or plain text (default: html).", 139 | "required": false 140 | } 141 | } 142 | }, 143 | "LinkCategory": { 144 | "extends" : "abstract.bitly.link", 145 | "httpMethod": "GET", 146 | "uri": "/v3/link/category", 147 | "summary" : "Returns the detected categories for a document, in descending order of confidence" 148 | }, 149 | "LinkSocial": { 150 | "extends" : "abstract.bitly.link", 151 | "httpMethod": "GET", 152 | "uri": "/v3/link/social", 153 | "summary" : "Returns the \"social score\" for a specified bitly link. Note that the social score are highly dependent upon activity (clicks) occurring on the bitly link. If there have not been clicks on a bitly link within the last 24 hours, it is possible a social score for that link does not exist." 154 | }, 155 | "LinkLocation": { 156 | "extends" : "abstract.bitly.link", 157 | "httpMethod": "GET", 158 | "uri": "/v3/link/location", 159 | "summary" : "Returns the significant locations for the bitly link or None if locations do not exist. Note that locations are highly dependent upon activity (clicks) occurring on the bitly link. If there have not been clicks on a bitly link within the last 24 hours, it is possible that location data for that link does not exist." 160 | }, 161 | "LinkLanguage": { 162 | "extends" : "abstract.bitly.link", 163 | "httpMethod": "GET", 164 | "uri": "/v3/link/language", 165 | "summary" : "Returns the significant languages for the bitly link. Note that languages are highly dependent upon activity (clicks) occurring on the bitly link. If there have not been clicks on a bitly link within the last 24 hours, it is possible that language data for that link does not exist." 166 | }, 167 | "Expand": { 168 | "extends" : "abstract.bitly", 169 | "httpMethod": "GET", 170 | "uri": "/v3/expand", 171 | "summary" : "Given a bitly URL or hash (or multiple), returns the target (long) URL.", 172 | "parameters": { 173 | "shortUrl": { 174 | "location": "query", 175 | "type" : "string", 176 | "description": "Refers to one or more bitly links. e.g.: http://bit.ly/1RmnUT or http://j.mp/1RmnUT.", 177 | "required": false 178 | }, 179 | "hash": { 180 | "location": "query", 181 | "type" : "string", 182 | "description": "Refers to one or more bitly hashes. e.g.: 2bYgqR or a-custom-name.", 183 | "required": false 184 | } 185 | } 186 | }, 187 | "Info": { 188 | "extends" : "abstract.bitly", 189 | "httpMethod": "GET", 190 | "uri": "/v3/info", 191 | "summary" : "This is used to return the page title for a given bitly link.", 192 | "parameters": { 193 | "hash": { 194 | "location": "query", 195 | "type" : "string", 196 | "description": "Refers to one or more bitly hashes. e.g.: 2bYgqR or a-custom-name.", 197 | "required": false 198 | }, 199 | "shortUrl": { 200 | "location": "query", 201 | "type" : "string", 202 | "description": "Refers to one or more bitly links e.g.: http://bit.ly/1RmnUT or http://j.mp/1RmnUT.", 203 | "required": false 204 | }, 205 | "expand_user": { 206 | "location": "query", 207 | "type" : "string", 208 | "description": "Optional true|false - include extra user info in response.", 209 | "required": false 210 | } 211 | } 212 | }, 213 | "LinkLookup": { 214 | "extends" : "abstract.bitly", 215 | "httpMethod": "GET", 216 | "uri": "/v3/link/lookup", 217 | "summary" : "This is used to query for a bitly link based on a long URL.", 218 | "parameters": { 219 | "url": { 220 | "location": "query", 221 | "type" : "string", 222 | "description": "One or more long URLs to lookup.", 223 | "required": false 224 | } 225 | } 226 | }, 227 | "Shorten": { 228 | "extends" : "abstract.bitly", 229 | "httpMethod": "GET", 230 | "uri": "/v3/shorten", 231 | "summary" : "Given a long URL, returns a bitly short URL.", 232 | "parameters": { 233 | "longUrl": { 234 | "location": "query", 235 | "type" : "string", 236 | "description": "A long URL to be shortened (example: http://iliveinperego.com/).", 237 | "required": true 238 | }, 239 | "domain": { 240 | "location": "query", 241 | "type" : "string", 242 | "description": "refers to a preferred domain; either bit.ly, j.mp, or bitly.com, for users who do NOT have a custom short domain set up with bitly.", 243 | "required": false 244 | } 245 | } 246 | }, 247 | "UserLink_edit": { 248 | "extends" : "abstract.bitly", 249 | "httpMethod": "GET", 250 | "uri": "/v3/user/link_edit", 251 | "summary" : "Changes link metadata in a user's history.", 252 | "parameters": { 253 | "link": { 254 | "location": "query", 255 | "type" : "string", 256 | "description": "The bitly link to be edited", 257 | "required": true 258 | }, 259 | "title": { 260 | "location": "query", 261 | "type" : "string", 262 | "description": "Optional - The title of this bitmark.", 263 | "required": false 264 | }, 265 | "note": { 266 | "location": "query", 267 | "type" : "string", 268 | "description": "Optional - A description of, or note about, this bitmark.", 269 | "required": false 270 | }, 271 | "private": { 272 | "location": "query", 273 | "type" : "string", 274 | "description": "Optional - Boolean true or false indicating privacy setting (defaults to user-level setting).", 275 | "required": false 276 | }, 277 | "user_ts": { 278 | "location": "query", 279 | "type" : "number", 280 | "description": "Optional - Timestamp as an integer epoch.", 281 | "required": false 282 | }, 283 | "archived": { 284 | "location": "query", 285 | "type" : "string", 286 | "description": "Optional - Boolean true or false indicating whether or not link is to be archived.", 287 | "required": false 288 | }, 289 | "edit": { 290 | "location": "query", 291 | "type" : "array", 292 | "description": "A comma separated string of fields to be edited. ie: to edit the note field you also need to pass edit=note.", 293 | "required": false 294 | } 295 | } 296 | }, 297 | "UserLink_lookup": { 298 | "extends" : "abstract.bitly", 299 | "httpMethod": "GET", 300 | "uri": "/v3/user/link_lookup", 301 | "summary" : "This is used to query for a bitly link shortened by the authenticated user based on a long URL.", 302 | "parameters": { 303 | "url": { 304 | "location": "query", 305 | "type" : "string", 306 | "description": "One or more long URLs to lookup.", 307 | "required": true 308 | } 309 | } 310 | }, 311 | "UserLink_save": { 312 | "extends" : "abstract.bitly", 313 | "httpMethod": "GET", 314 | "uri": "/v3/user/link_save", 315 | "summary" : "Saves a link as a bitmark in a user's history, with optional pre-set metadata. (Also returns a short URL for that link.)", 316 | "parameters": { 317 | "longUrl": { 318 | "location": "query", 319 | "type" : "string", 320 | "description": "The URL to be saved as a bitmark.", 321 | "required": true 322 | }, 323 | "title": { 324 | "location": "query", 325 | "type" : "string", 326 | "description": "Optional - The title of this bitmark.", 327 | "required": false 328 | }, 329 | "note": { 330 | "location": "query", 331 | "type" : "string", 332 | "description": "Optional - A description of, or note about, this bitmark.", 333 | "required": false 334 | }, 335 | "private": { 336 | "location": "query", 337 | "type" : "string", 338 | "description": "Optional - Boolean true or false indicating privacy setting (defaults to user-level setting).", 339 | "required": false 340 | }, 341 | "user_ts": { 342 | "location": "query", 343 | "type" : "integer", 344 | "description": "Optional - Timestamp as an integer epoch.", 345 | "required": false 346 | } 347 | } 348 | }, 349 | "UserSave_custom_domain_keyword": { 350 | "extends" : "abstract.bitly", 351 | "httpMethod": "GET", 352 | "uri": "/v3/user/save_custom_domain_keyword", 353 | "summary" : "Save a custom keyword for a custom short domain. This endpoint is only available to paid customers.", 354 | "parameters": { 355 | "keyword_link": { 356 | "location": "query", 357 | "type" : "string", 358 | "description": "The short domain and keyword combination", 359 | "required": true 360 | }, 361 | "target_link": { 362 | "location": "query", 363 | "type" : "string", 364 | "description": "The bitly short URL the specified keyword will map to", 365 | "required": true 366 | }, 367 | "overwrite" : { 368 | "location": "query", 369 | "type" : "string", 370 | "description": "Optional - Boolean true or false indicating whether or not to overwrite existing entry if one exists (defaults to false).", 371 | "required": false 372 | } 373 | } 374 | }, 375 | "abstract.bitly.link_metrics": { 376 | "extends": "abstract.bitly", 377 | "parameters": { 378 | "link": { 379 | "location": "query", 380 | "type" : "string", 381 | "description": "A bitly link.", 382 | "required": true 383 | }, 384 | "unit": { 385 | "location": "query", 386 | "type" : "string", 387 | "description": "minute, hour, day, week or month, default: day | Note: when unit is minute the maximum value for units is 60.", 388 | "required": false 389 | }, 390 | "units": { 391 | "location": "query", 392 | "type" : "string", 393 | "description": "an integer representing the time units to query data for. Pass -1 to return all units of time.", 394 | "required": false 395 | }, 396 | "timezone": { 397 | "location": "query", 398 | "type" : "string", 399 | "description": "An integer hour offset from UTC (-14 to 14), or a timezone string default: America/New_York.", 400 | "required": false 401 | }, 402 | "limit": { 403 | "location": "query", 404 | "type" : "number", 405 | "description": "1 to 1000 (default=100).", 406 | "required": false 407 | }, 408 | "unit_reference_ts": { 409 | "location": "query", 410 | "type" : "number", 411 | "description": "An epoch timestamp, indicating the most recent time for which to pull metrics, default: now. Note: the value of unit_reference_ts rounds to the nearest unit. Note: historical data is stored hourly beyond the most recent 60 minutes. If a unit_reference_ts is specified, unit cannot be minute.", 412 | "required": false 413 | } 414 | } 415 | }, 416 | "LinkClicks": { 417 | "extends" : "abstract.bitly.link_metrics", 418 | "httpMethod": "GET", 419 | "uri": "/v3/link/clicks", 420 | "summary" : "Returns the number of clicks on a single bitly link.", 421 | "parameters": { 422 | "rollup": { 423 | "location": "query", 424 | "type" : "string", 425 | "description": "True or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 426 | "required": true 427 | } 428 | } 429 | }, 430 | "LinkCountries": { 431 | "extends" : "abstract.bitly.link_metrics", 432 | "httpMethod": "GET", 433 | "uri": "/v3/link/countries", 434 | "summary" : "Returns metrics about the countries referring click traffic to a single bitly link." 435 | }, 436 | "abstract.bitly.link_encoders": { 437 | "extends" : "abstract.bitly", 438 | "parameters": { 439 | "link": { 440 | "location": "query", 441 | "type" : "string", 442 | "description": "A bitly link.", 443 | "required": true 444 | }, 445 | "my_network": { 446 | "location": "query", 447 | "type" : "string", 448 | "description": "true or false - restrict to my network.", 449 | "required": false 450 | }, 451 | "subaccounts": { 452 | "location": "query", 453 | "type" : "string", 454 | "description": "Only available to enterprise accounts. true or false - restrict to this enterprise account and its subaccounts", 455 | "required": false 456 | }, 457 | "limit": { 458 | "location": "query", 459 | "type" : "number", 460 | "description": "Integer in the range of 1 to 25 that specifies the number of records to return (default: 10).", 461 | "required": false 462 | }, 463 | "expand_user": { 464 | "location": "query", 465 | "type" : "string", 466 | "description": "true or false - include display names of encoders.", 467 | "required": false 468 | } 469 | } 470 | }, 471 | "LinkEncoders": { 472 | "extends" : "abstract.bitly.link_encoders", 473 | "httpMethod": "GET", 474 | "uri": "/v3/link/encoders", 475 | "summary" : "Returns users who have encoded this link (optionally only those in the requesting user's social graph)." 476 | }, 477 | "LinkEncoders_by_count": { 478 | "extends" : "abstract.bitly.link_encoders", 479 | "httpMethod": "GET", 480 | "uri": "/v3/link/encoders_by_count", 481 | "summary" : "Returns users who have encoded this link (optionally only those in the requesting user's social graph), sorted by the number of clicks on each encoding user's link. Note: The response will only contain users whose links have gotten at least one click, and will not contain any users whose links are private." 482 | }, 483 | "LinkEncoders_count": { 484 | "extends" : "abstract.bitly", 485 | "httpMethod": "GET", 486 | "uri": "/v3/link/encoders_count", 487 | "summary" : "Returns the number of users who have shortened (encoded) a single bitly link.", 488 | "parameters": { 489 | "link": { 490 | "location": "query", 491 | "type" : "string", 492 | "description": "A bitly link.", 493 | "required": true 494 | } 495 | } 496 | }, 497 | "LinkReferrers": { 498 | "extends" : "abstract.bitly.link_metrics", 499 | "httpMethod": "GET", 500 | "uri": "/v3/link/referrers", 501 | "summary" : "Returns metrics about the pages referring click traffic to a single bitly link." 502 | }, 503 | "LinkReferrers_by_domain": { 504 | "extends" : "abstract.bitly.link_metrics", 505 | "httpMethod": "GET", 506 | "uri": "/v3/link/referrers_by_domain", 507 | "summary" : "Returns metrics about the pages referring click traffic to a single bitly link." 508 | }, 509 | "LinkReferring_domains": { 510 | "extends" : "abstract.bitly.link_metrics", 511 | "httpMethod": "GET", 512 | "uri": "/v3/link/referring_domains", 513 | "summary" : "Returns metrics about the pages referring click traffic to a single bitly link." 514 | }, 515 | "abstract.bitly.user": { 516 | "parameters": { 517 | "unit": { 518 | "location": "query", 519 | "type" : "string", 520 | "description": "minute, hour, day, week or month, default: day | Note: when unit is minute the maximum value for units is 60.", 521 | "required": true 522 | }, 523 | "units": { 524 | "location": "query", 525 | "type" : "string", 526 | "description": "an integer representing the time units to query data for. Pass -1 to return all units of time.", 527 | "required": true 528 | }, 529 | "timezone": { 530 | "location": "query", 531 | "type" : "string", 532 | "description": "An integer hour offset from UTC (-14 to 14), or a timezone string default: America/New_York.", 533 | "required": true 534 | }, 535 | "limit": { 536 | "location": "query", 537 | "type" : "number", 538 | "description": "1 to 1000 (default=100).", 539 | "required": false 540 | }, 541 | "unit_reference_ts": { 542 | "location": "query", 543 | "type" : "number", 544 | "description": "An epoch timestamp, indicating the most recent time for which to pull metrics, default: now. Note: the value of unit_reference_ts rounds to the nearest unit. Note: historical data is stored hourly beyond the most recent 60 minutes. If a unit_reference_ts is specified, unit cannot be minute.", 545 | "required": true 546 | } 547 | } 548 | }, 549 | "UserClicks": { 550 | "extends" : "abstract.bitly.user", 551 | "httpMethod": "GET", 552 | "uri": "/v3/user/clicks", 553 | "summary" : "Returns the aggregate number of clicks on all of the authenticated user's bitly links.", 554 | "parameters": { 555 | "rollup": { 556 | "location": "query", 557 | "type" : "string", 558 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 559 | "required": true 560 | } 561 | } 562 | }, 563 | "UserCountries": { 564 | "extends" : "abstract.bitly.user", 565 | "httpMethod": "GET", 566 | "uri": "/v3/user/countries", 567 | "summary" : "Returns aggregate metrics about the countries referring click traffic to all of the authenticated user's bitly links.", 568 | "parameters": { 569 | "rollup": { 570 | "location": "query", 571 | "type" : "string", 572 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 573 | "required": true 574 | } 575 | } 576 | }, 577 | "UserPopular_earned_by_clicks": { 578 | "extends" : "abstract.bitly.user", 579 | "httpMethod": "GET", 580 | "uri": "/v3/user/popular_earned_by_clicks", 581 | "summary" : "Returns the top links to your tracking domain (or domains) created by users not associated with your account, ordered by clicks. Users can register a tracking domain from their bitly settings page. This endpoint is only available to paid customers.", 582 | "parameters": { 583 | "domain": { 584 | "location": "query", 585 | "type" : "string", 586 | "description": "A tracking domain as returned from /v3/user/tracking_domain_list.", 587 | "required": true 588 | } 589 | } 590 | }, 591 | "UserPopular_earned_by_shortens": { 592 | "extends" : "abstract.bitly.user", 593 | "httpMethod": "GET", 594 | "uri": "/v3/user/popular_earned_by_shortens", 595 | "summary" : "Returns the top links to your tracking domain (or domains) created by users not associated with your account, ordered by shortens. Users can register a tracking domain from their bitly settings page. This endpoint is only available to paid customers.", 596 | "parameters": { 597 | "domain": { 598 | "location": "query", 599 | "type" : "string", 600 | "description": "A tracking domain as returned from /v3/user/tracking_domain_list.", 601 | "required": true 602 | } 603 | } 604 | }, 605 | "UserPopular_links": { 606 | "extends" : "abstract.bitly.user", 607 | "httpMethod": "GET", 608 | "uri": "/v3/user/popular_links", 609 | "summary" : "Returns the authenticated user's most-clicked bitly links (ordered by number of clicks) in a given time period. Note: This replaces the realtime_links endpoint." 610 | }, 611 | "UserPopular_owned_by_clicks": { 612 | "extends" : "abstract.bitly.user", 613 | "httpMethod": "GET", 614 | "uri": "/v3/user/popular_owned_by_clicks", 615 | "summary" : "Returns the top links to your tracking domain (or domains) created by you or your subaccounts ordered by clicks. Users can register a tracking domain from their bitly settings page. This endpoint is only available to paid customers..", 616 | "parameters": { 617 | "domain": { 618 | "location": "query", 619 | "type" : "string", 620 | "description": "A tracking domain as returned from /v3/user/tracking_domain_list.", 621 | "required": true 622 | }, 623 | "subaccount": { 624 | "location": "query", 625 | "type" : "string", 626 | "description": "Restrict to links created by this subaccount (may be specified multiple times).", 627 | "required": true 628 | } 629 | } 630 | }, 631 | "UserPopular_owned_by_shortens": { 632 | "extends" : "abstract.bitly.user", 633 | "httpMethod": "GET", 634 | "uri": "/v3/user/popular_earned_by_shortens", 635 | "summary" : "Returns the top links to your tracking domain (or domains) created by you or your subaccounts ordered by number of shortens. Users can register a tracking domain from their bitly settings page. This endpoint is only available to paid customers.", 636 | "parameters": { 637 | "domain": { 638 | "location": "query", 639 | "type" : "string", 640 | "description": "A tracking domain as returned from /v3/user/tracking_domain_list.", 641 | "required": true 642 | }, 643 | "subaccount": { 644 | "location": "query", 645 | "type" : "string", 646 | "description": "Restrict to links created by this subaccount (may be specified multiple times).", 647 | "required": true 648 | } 649 | } 650 | }, 651 | "UserReferrers": { 652 | "extends" : "abstract.bitly.user", 653 | "httpMethod": "GET", 654 | "uri": "/v3/user/referrers", 655 | "summary" : "Returns aggregate metrics about the pages referring click traffic to all of the authenticated user's bitly links.", 656 | "parameters": { 657 | "rollup": { 658 | "location": "query", 659 | "type" : "string", 660 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 661 | "required": true 662 | } 663 | } 664 | }, 665 | "UserReferring_domains": { 666 | "extends" : "abstract.bitly.user", 667 | "httpMethod": "GET", 668 | "uri": "/v3/user/referring_domains", 669 | "summary" : "Returns aggregate metrics about the domains referring click traffic to all of the authenticated user's bitly links.", 670 | "parameters": { 671 | "rollup": { 672 | "location": "query", 673 | "type" : "string", 674 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 675 | "required": true 676 | } 677 | } 678 | }, 679 | "UserShare_counts": { 680 | "extends" : "abstract.bitly.user", 681 | "httpMethod": "GET", 682 | "uri": "/v3/user/share_counts", 683 | "summary" : "Returns the number of shares by the authenticated user in a given time period.", 684 | "parameters": { 685 | "rollup": { 686 | "location": "query", 687 | "type" : "string", 688 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 689 | "required": true 690 | } 691 | } 692 | }, 693 | "UserShare_counts_by_share_type": { 694 | "extends" : "abstract.bitly.user", 695 | "httpMethod": "GET", 696 | "uri": "/v3/user/share_counts_by_share_type", 697 | "summary" : "Returns the number of shares by the authenticated user, broken down by share type (ie: twitter, facebook, email) in a given time period.", 698 | "parameters": { 699 | "rollup": { 700 | "location": "query", 701 | "type" : "string", 702 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 703 | "required": true 704 | } 705 | } 706 | }, 707 | "UserShorten_counts": { 708 | "extends" : "abstract.bitly.user", 709 | "httpMethod": "GET", 710 | "uri": "/v3/user/shorten_counts", 711 | "summary" : "Returns the number of links shortened (encoded) in a given time period by the authenticated user.", 712 | "parameters": { 713 | "rollup": { 714 | "location": "query", 715 | "type" : "string", 716 | "description": "true or false. Return data for multiple units rolled up to a single result instead of a separate value for each period of time.", 717 | "required": true 718 | } 719 | } 720 | } 721 | } 722 | } -------------------------------------------------------------------------------- /src/Subscribers/ArrayAggregatorSubscriber.php: -------------------------------------------------------------------------------- 1 | array('changeAggregator', 255)); 21 | } 22 | 23 | /** 24 | * Change aggregator 25 | * 26 | * @param Event $event 27 | */ 28 | public function changeAggregator(Event $event) 29 | { 30 | $event['command']->getRequest()->getQuery()->setAggregator(new CommaAggregator()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Subscribers/ResponseStandardizationSubscriber.php: -------------------------------------------------------------------------------- 1 | array('StandardizeResponse', 255)); 17 | } 18 | 19 | /** 20 | * @param Event $event 21 | * - Bitly always returns 200 as status code. This set the correct status code for responses. 22 | * - In case of a valid response from Bitly API we just return the 'data' section of the original response 23 | */ 24 | public function standardizeResponse(Event $event) 25 | { 26 | 27 | $full_json_response = $event['response']->json(); 28 | 29 | if ($full_json_response['status_code'] <= 400) 30 | return $event['response']->setBody(json_encode($full_json_response['data'])); 31 | 32 | $event['response']->setStatus($full_json_response['status_code'], $full_json_response['status_txt']); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/ClientTest.php: -------------------------------------------------------------------------------- 1 | bitly_client = new Hpatoio\Bitly\Client("non_existing_token_just_for_test"); 14 | } 15 | 16 | private function initBitlyClient($data) 17 | { 18 | 19 | $bitlyResponse = new \Guzzle\Http\Message\Response(200); 20 | $bitlyResponse->setBody($data); 21 | 22 | $plugin = new \Guzzle\Plugin\Mock\MockPlugin(); 23 | $plugin->addResponse($bitlyResponse); 24 | 25 | $this->bitly_client->addSubscriber($plugin); 26 | 27 | } 28 | 29 | public function testAccessTokenIsAddedToRequest() 30 | { 31 | $this->initBitlyClient($this->response_error); 32 | $command = $this->bitly_client->getCommand('Highvalue', array("limit" => 3)); 33 | $this->assertEquals($command->prepare()->getQuery()->get("access_token"), "non_existing_token_just_for_test"); 34 | } 35 | 36 | public function testExceptionOnErrorResponse() 37 | { 38 | 39 | $this->initBitlyClient($this->response_error); 40 | 41 | try { 42 | $this->bitly_client->Highvalue(array("limit" => 2)); 43 | } catch ( \Guzzle\Http\Exception\ServerErrorResponseException $expected ) { 44 | return; 45 | } 46 | 47 | $this->fail('An expected exception has not been raised.'); 48 | 49 | } 50 | 51 | } 52 | --------------------------------------------------------------------------------