├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── API-GUIDE-v2.md ├── API-GUIDE-v3.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── ClientFactory.php ├── Contract │ └── Http.php ├── Exception │ ├── ClientConfigurationException.php │ ├── HttpException.php │ └── InvalidVersionException.php ├── Tool │ ├── ConfigurationTrait.php │ └── HttpTrait.php ├── Version.php ├── v2 │ └── Client.php └── v3 │ ├── Client.php │ └── RateLimit.php └── tests ├── ClientFactoryTest.php ├── Tool └── HttpTraitTest.php ├── v2 ├── ClientTest.php ├── business_response.json ├── error_response.json └── search_response.json └── v3 ├── ClientTest.php ├── autocomplete_response.json ├── business_response.json ├── business_reviews_response.json ├── business_search_by_phone_response.json ├── business_search_response.json └── error_response.json /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /vendor 3 | composer.phar 4 | composer.lock 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: [tests/*] 3 | checks: 4 | php: 5 | code_rating: true 6 | remove_extra_empty_lines: true 7 | remove_php_closing_tag: true 8 | remove_trailing_whitespace: true 9 | fix_use_statements: 10 | remove_unused: true 11 | preserve_multiple: false 12 | preserve_blanklines: true 13 | order_alphabetically: true 14 | fix_php_opening_tag: true 15 | fix_linefeed: true 16 | fix_line_ending: true 17 | fix_identation_4spaces: true 18 | fix_doc_comments: true 19 | tools: 20 | external_code_coverage: 21 | timeout: 600 22 | runs: 2 23 | php_analyzer: true 24 | php_code_coverage: false 25 | php_code_sniffer: 26 | config: 27 | standard: PSR2 28 | filter: 29 | paths: ['src'] 30 | php_loc: 31 | enabled: true 32 | excluded_dirs: [vendor, tests] 33 | php_cpd: 34 | enabled: true 35 | excluded_dirs: [vendor, tests] 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | matrix: 4 | include: 5 | - php: 5.6 6 | - php: 7.0 7 | - php: 7.1 8 | - php: 7.2 9 | - php: nightly 10 | - php: hhvm-3.6 11 | sudo: required 12 | dist: trusty 13 | group: edge 14 | - php: hhvm-3.9 15 | sudo: required 16 | dist: trusty 17 | group: edge 18 | - php: hhvm-3.12 19 | sudo: required 20 | dist: trusty 21 | group: edge 22 | - php: hhvm-3.15 23 | sudo: required 24 | dist: trusty 25 | group: edge 26 | - php: hhvm-nightly 27 | sudo: required 28 | dist: trusty 29 | group: edge 30 | fast_finish: true 31 | allow_failures: 32 | - php: nightly 33 | - php: hhvm-nightly 34 | 35 | before_script: 36 | - travis_retry composer self-update 37 | - travis_retry composer install --no-interaction --prefer-source --dev 38 | - travis_retry phpenv rehash 39 | 40 | script: 41 | - ./vendor/bin/phpcs --standard=psr2 src/ 42 | - ./vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover 43 | 44 | after_script: 45 | - if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "7.0" ]; then wget https://scrutinizer-ci.com/ocular.phar; fi 46 | - if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ "$TRAVIS_PHP_VERSION" != "7.0" ]; then php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi 47 | -------------------------------------------------------------------------------- /API-GUIDE-v2.md: -------------------------------------------------------------------------------- 1 | # Yelp PHP Client - v2 2 | 3 | ## Create client explicitly 4 | 5 | ```php 6 | $client = new \Stevenmaguire\Yelp\v2\Client(array( 7 | 'consumerKey' => 'YOUR COSUMER KEY', 8 | 'consumerSecret' => 'YOUR CONSUMER SECRET', 9 | 'token' => 'YOUR TOKEN', 10 | 'tokenSecret' => 'YOUR TOKEN SECRET', 11 | 'apiHost' => 'api.yelp.com' // Optional, default 'api.yelp.com' 12 | )); 13 | ``` 14 | 15 | ## Search by keyword and location 16 | 17 | ```php 18 | $results = $client->search(array('term' => 'Sushi', 'location' => 'Chicago, IL')); 19 | ``` 20 | 21 | ## Search by phone number 22 | 23 | ```php 24 | $results = $client->searchByPhone(array('phone' => '867-5309')); 25 | ``` 26 | 27 | ## Locate details for a specific business by Yelp business id 28 | 29 | ```php 30 | $business = $client->getBusiness('union-chicago-3'); 31 | ``` 32 | 33 | You may include [action links](http://engineeringblog.yelp.com/2015/07/yelp-api-now-returns-action-links.html) in your results by passing additional parameters with your request. 34 | 35 | ```php 36 | $resultsWithActionLinks = $client->getBusiness('union-chicago-3', [ 37 | 'actionLinks' => true 38 | ]); 39 | ``` 40 | 41 | ## Configure defaults 42 | 43 | ```php 44 | $client->setDefaultLocation('Chicago, IL') // default location for all searches if location not provided 45 | ->setDefaultTerm('Sushi') // default keyword for all searches if term not provided 46 | ->setSearchLimit(20); // number of records to return 47 | ``` 48 | 49 | ## Exceptions 50 | 51 | If the API request results in an Http error, the client will throw a `\Stevenmaguire\Yelp\Exception\HttpException` that includes the response body, as a string, from the Yelp API. 52 | 53 | ```php 54 | try { 55 | $business = $client->getBusiness('union-chicago-3'); 56 | } catch (\Stevenmaguire\Yelp\Exception\HttpException $e) { 57 | $responseBody = $e->getResponseBody(); // string from Http request 58 | $responseBodyObject = json_decode($responseBody); 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /API-GUIDE-v3.md: -------------------------------------------------------------------------------- 1 | # Yelp PHP Client - v3 (Fusion) 2 | 3 | ## Create client explicitly 4 | 5 | Yelp API version 3 (Fusion) [requires an OAuth2 access token to authenticate each request](https://www.yelp.com/developers/documentation/v3/authentication). The [oauth2-yelp](https://github.com/stevenmaguire/oauth2-yelp) is available to help obtain an access token. 6 | 7 | ```php 8 | // Get access token via oauth2-yelp library 9 | $provider = new \Stevenmaguire\OAuth2\Client\Provider\Yelp([ 10 | 'clientId' => '{yelp-client-id}', 11 | 'clientSecret' => '{yelp-client-secret}' 12 | ]); 13 | $accessToken = (string) $provider->getAccessToken('client_credentials'); 14 | 15 | // Provide the access token to the yelp-php client 16 | $client = new \Stevenmaguire\Yelp\v3\Client(array( 17 | 'accessToken' => $accessToken, 18 | 'apiHost' => 'api.yelp.com' // Optional, default 'api.yelp.com' 19 | )); 20 | ``` 21 | 22 | > Prior to December 7, 2017 `accessToken` was required to authenticate requests. Since then, `apiKey` is the preferred authentication method. This library supports both `accessToken` and `apiKey`, prioritizing `apiKey` over `accessToken` if both are provided. 23 | > 24 | > https://www.yelp.com/developers/documentation/v3/authentication#where-is-my-client-secret-going 25 | 26 | 27 | ## Search for businesses 28 | 29 | See also [https://www.yelp.com/developers/documentation/v3/business_search](https://www.yelp.com/developers/documentation/v3/business_search) 30 | 31 | ```php 32 | $parameters = [ 33 | 'term' => 'bars', 34 | 'location' => 'Chicago, IL', 35 | 'latitude' => 41.8781, 36 | 'longitude' => 87.6298, 37 | 'radius' => 10, 38 | 'categories' => ['bars', 'french'], 39 | 'locale' => 'en_US', 40 | 'limit' => 10, 41 | 'offset' => 2, 42 | 'sort_by' => 'best_match', 43 | 'price' => '1,2,3', 44 | 'open_now' => true, 45 | 'open_at' => 1234566, 46 | 'attributes' => ['hot_and_new','deals'] 47 | ]; 48 | 49 | $results = $client->getBusinessesSearchResults($parameters); 50 | ``` 51 | 52 | ## Search for businesses by phone number 53 | 54 | See also [https://www.yelp.com/developers/documentation/v3/business_search_phone](https://www.yelp.com/developers/documentation/v3/business_search_phone) 55 | 56 | ```php 57 | $results = $client->getBusinessesSearchResultsByPhone('312-867-5309'); 58 | ``` 59 | 60 | ## Retrieve details for a specific business by Yelp business id 61 | 62 | See also [https://www.yelp.com/developers/documentation/v3/business](https://www.yelp.com/developers/documentation/v3/business) 63 | 64 | ```php 65 | $parameters = [ 66 | 'locale' => 'en_US', 67 | ]; 68 | 69 | $business = $client->getBusiness('the-motel-bar-chicago', $parameters); 70 | ``` 71 | 72 | ## Retrieve reviews for a specific business by Yelp business id 73 | 74 | See also [https://www.yelp.com/developers/documentation/v3/business_reviews](https://www.yelp.com/developers/documentation/v3/business_reviews) 75 | 76 | ```php 77 | $parameters = [ 78 | 'locale' => 'en_US', 79 | ]; 80 | 81 | $reviews = $client->getBusinessReviews('the-motel-bar-chicago', $parameters); 82 | ``` 83 | 84 | ## Retrieve autocomplete suggestions 85 | 86 | See also [https://www.yelp.com/developers/documentation/v3/autocomplete](https://www.yelp.com/developers/documentation/v3/autocomplete) 87 | 88 | ```php 89 | $parameters = [ 90 | 'text' => 'Mot', 91 | 'latitude' => 41.8781, 92 | 'longitude' => 87.6298, 93 | 'locale' => 'en_US' 94 | ]; 95 | 96 | $results = $client->getAutocompleteResults($parameters); 97 | ``` 98 | 99 | ## Search for transactions by type 100 | 101 | See also [https://www.yelp.com/developers/documentation/v3/transactions_search](https://www.yelp.com/developers/documentation/v3/transactions_search) 102 | 103 | ```php 104 | $parameters = [ 105 | 'latitude' => 41.8781, 106 | 'longitude' => 87.6298, 107 | 'location' => 'Chicago, IL' 108 | ]; 109 | 110 | $results = $client->getTransactionsSearchResultsByType('delivery', $parameters); 111 | ``` 112 | 113 | ## Exceptions 114 | 115 | If the API request results in an Http error, the client will throw a `Stevenmaguire\Yelp\Exception\HttpException` that includes the response body, as a string, from the Yelp API. 116 | 117 | ```php 118 | try { 119 | $business = $client->getBusiness('the-motel-bar-chicago'); 120 | } catch (\Stevenmaguire\Yelp\Exception\HttpException $e) { 121 | $responseBody = $e->getResponseBody(); // string from Http request 122 | $responseBodyObject = json_decode($responseBody); 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All Notable changes to `yelp-php` will be documented in this file 3 | 4 | ## 2.2.0 - 2018-12-12 5 | 6 | ### Added 7 | - Support for reporting Daily Rate Limits from previous successful HTTP requests to Yelp's v3 service. 8 | 9 | ### Deprecated 10 | - Nothing 11 | 12 | ### Fixed 13 | - Nothing 14 | 15 | ### Removed 16 | - Nothing 17 | 18 | ### Security 19 | - Nothing 20 | 21 | ## 2.1.0 - 2018-02-10 22 | 23 | ### Added 24 | - Support for API Keys alongside Access Tokens; preference given to API Keys (https://www.yelp.com/developers/documentation/v3/authentication#where-is-my-client-secret-going) 25 | 26 | ### Deprecated 27 | - Nothing 28 | 29 | ### Fixed 30 | - Nothing 31 | 32 | ### Removed 33 | - Nothing 34 | 35 | ### Security 36 | - Nothing 37 | 38 | ## 2.0.0 - 2017-06-26 39 | 40 | ### Added 41 | - Support for Yelp API v3 (Fusion) 42 | 43 | ### Deprecated 44 | - Nothing 45 | 46 | ### Fixed 47 | - Nothing 48 | 49 | ### Removed 50 | - Nothing 51 | 52 | ### Security 53 | - Nothing 54 | 55 | ## 1.4.3 - 2016-03-28 56 | 57 | ### Added 58 | - Support for additional parameters on `getBusiness`, enables support for actionLinks 59 | 60 | ### Deprecated 61 | - Nothing 62 | 63 | ### Fixed 64 | - Nothing 65 | 66 | ### Removed 67 | - Nothing 68 | 69 | ### Security 70 | - Nothing 71 | 72 | ## 1.4.2 - 2015-11-23 73 | 74 | ### Added 75 | - Nothing 76 | 77 | ### Deprecated 78 | - Nothing 79 | 80 | ### Fixed 81 | - OAuth1 subscriber configuration issue. (https://github.com/stevenmaguire/yelp-php/issues/9) 82 | 83 | ### Removed 84 | - Nothing 85 | 86 | ### Security 87 | - Nothing 88 | 89 | ## 1.4.1 - 2015-11-17 90 | 91 | ### Added 92 | - Improved test suite performance 93 | 94 | ### Deprecated 95 | - Nothing 96 | 97 | ### Fixed 98 | - Nothing 99 | 100 | ### Removed 101 | - Nothing 102 | 103 | ### Security 104 | - Nothing 105 | 106 | ## 1.4.0 - 2015-08-27 107 | 108 | ### Added 109 | - Upgrade guzzle dependency 110 | 111 | ### Deprecated 112 | - Nothing 113 | 114 | ### Fixed 115 | - Nothing 116 | 117 | ### Removed 118 | - Nothing 119 | 120 | ### Security 121 | - Nothing 122 | 123 | ## 1.3.0 - 2015-08-14 124 | 125 | ### Added 126 | - Nothing 127 | 128 | ### Deprecated 129 | - Nothing 130 | 131 | ### Fixed 132 | - Nothing 133 | 134 | ### Removed 135 | - Superfluous dependency 136 | 137 | ### Security 138 | - Nothing 139 | 140 | ## 1.2.0 - 2015-05-21 141 | 142 | ### Added 143 | - Added search by phone number method 144 | 145 | ### Deprecated 146 | - Nothing 147 | 148 | ### Fixed 149 | - Nothing 150 | 151 | ### Removed 152 | - Nothing 153 | 154 | ### Security 155 | - Nothing 156 | 157 | ## 1.1.0 - 2015-04-23 158 | 159 | ### Added 160 | - Added Http response body to Exception 161 | 162 | ### Deprecated 163 | - Nothing 164 | 165 | ### Fixed 166 | - Nothing 167 | 168 | ### Removed 169 | - Nothing 170 | 171 | ### Security 172 | - Nothing 173 | 174 | ## 1.0.7 - 2015-04-23 175 | 176 | ### Added 177 | - Added support to urlencode business ids before fetching business record 178 | 179 | ### Deprecated 180 | - Nothing 181 | 182 | ### Fixed 183 | - Nothing 184 | 185 | ### Removed 186 | - Nothing 187 | 188 | ### Security 189 | - Nothing 190 | 191 | ## 1.0.5 - 2015-03-05 192 | 193 | ### Added 194 | - Switched OAuth1 support from native cURL to Guzzle and its OAuth1 Subscriber plugin 195 | 196 | ### Deprecated 197 | - Nothing 198 | 199 | ### Fixed 200 | - Nothing 201 | 202 | ### Removed 203 | - Nothing 204 | 205 | ### Security 206 | - Nothing 207 | 208 | ## 1.0.0 - 2015-01-10 209 | 210 | ### Added 211 | - Business lookup by ID 212 | - Search by term and location 213 | - Set default term 214 | - Set default location 215 | - Set search record limit 216 | 217 | ### Deprecated 218 | - Nothing 219 | 220 | ### Fixed 221 | - Nothing 222 | 223 | ### Removed 224 | - Nothing 225 | 226 | ### Security 227 | - Nothing 228 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/stevenmaguire/yelp-php). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ ./vendor/bin/phpunit 29 | ``` 30 | 31 | 32 | ## Running PHP Code Sniffer 33 | 34 | ``` bash 35 | $ ./vendor/bin/phpcs src --standard=psr2 -sp 36 | ``` 37 | 38 | 39 | **Happy coding**! 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Steven Maguire 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yelp PHP Client 2 | 3 | [![Latest Version](https://img.shields.io/github/release/stevenmaguire/yelp-php.svg?style=flat-square)](https://github.com/stevenmaguire/yelp-php/releases) 4 | [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 5 | [![Build Status](https://img.shields.io/travis/stevenmaguire/yelp-php/master.svg?style=flat-square&1)](https://travis-ci.org/stevenmaguire/yelp-php) 6 | [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/stevenmaguire/yelp-php.svg?style=flat-square)](https://scrutinizer-ci.com/g/stevenmaguire/yelp-php/code-structure) 7 | [![Quality Score](https://img.shields.io/scrutinizer/g/stevenmaguire/yelp-php.svg?style=flat-square)](https://scrutinizer-ci.com/g/stevenmaguire/yelp-php) 8 | [![Total Downloads](https://img.shields.io/packagist/dt/stevenmaguire/yelp-php.svg?style=flat-square)](https://packagist.org/packages/stevenmaguire/yelp-php) 9 | 10 | A PHP client for authenticating with Yelp using OAuth and consuming the API. 11 | 12 | ## Install 13 | 14 | Via Composer 15 | 16 | ``` bash 17 | $ composer require stevenmaguire/yelp-php 18 | ``` 19 | 20 | ## Usage 21 | 22 | This package currently supports `v2` and `v3` (Fusion) of the Yelp API. Each version of the Yelp API maps to a different client, as the APIs are very different. Each client has separate documentation; links provided below. 23 | 24 | ### Create client 25 | 26 | Each version of the Yelp API maps to a different client, as the APIs are very different. A client factory is available to create appropriate clients. 27 | 28 | #### v2 Client Example 29 | 30 | ```php 31 | $options = array( 32 | 'consumerKey' => 'YOUR COSUMER KEY', 33 | 'consumerSecret' => 'YOUR CONSUMER SECRET', 34 | 'token' => 'YOUR TOKEN', 35 | 'tokenSecret' => 'YOUR TOKEN SECRET', 36 | 'apiHost' => 'api.yelp.com' // Optional, default 'api.yelp.com' 37 | ); 38 | 39 | $client = \Stevenmaguire\Yelp\ClientFactory::makeWith( 40 | $options, 41 | \Stevenmaguire\Yelp\Version::TWO 42 | ); 43 | ``` 44 | 45 | #### v3 Client Example 46 | 47 | ```php 48 | $options = array( 49 | 'accessToken' => 'YOUR ACCESS TOKEN', // Required, unless apiKey is provided 50 | 'apiHost' => 'api.yelp.com', // Optional, default 'api.yelp.com', 51 | 'apiKey' => 'YOUR ACCESS TOKEN', // Required, unless accessToken is provided 52 | ); 53 | 54 | $client = \Stevenmaguire\Yelp\ClientFactory::makeWith( 55 | $options, 56 | \Stevenmaguire\Yelp\Version::THREE 57 | ); 58 | ``` 59 | 60 | > Prior to December 7, 2017 `accessToken` was required to authenticate requests. Since then, `apiKey` is the preferred authentication method. This library supports both `accessToken` and `apiKey`, prioritizing `apiKey` over `accessToken` if both are provided. 61 | > 62 | > https://www.yelp.com/developers/documentation/v3/authentication#where-is-my-client-secret-going 63 | 64 | Version | Constant | Documentation 65 | --------|----------|-------------- 66 | v2 | `Stevenmaguire\Yelp\Version::TWO` | [API-GUIDE-v2.md](API-GUIDE-v2.md) 67 | v3 | `Stevenmaguire\Yelp\Version::THREE` | [API-GUIDE-v3.md](API-GUIDE-v3.md) 68 | 69 | ##### Get Rate Limit data from most recent request 70 | 71 | For the v3 client, [rate limiting data](https://www.yelp.com/developers/documentation/v3/rate_limiting) is avaiable after a recent request. 72 | 73 | ```php 74 | // $latestRateLimit will be null if an http request hasn't been successfully completed. 75 | $latestRateLimit = $client->getRateLimit(); 76 | 77 | // The maximum number of calls you can make per day 78 | $latestDailyLimit = $latestRateLimit->dailyLimit; 79 | 80 | // The number of calls remaining within the current day 81 | $latestRemaining = $latestRateLimit->remaining; 82 | 83 | // The time at which the current rate limiting window will expire as an ISO 8601 timestamp 84 | $latestResetTime = $latestRateLimit->resetTime; 85 | 86 | // The time at which the current rate limiting data was observed as an ISO 8601 timestamp 87 | $latestCreatedAt = $latestRateLimit->createdAt; 88 | ``` 89 | 90 | ### Exceptions 91 | 92 | If the API request results in an Http error, the client will throw a `Stevenmaguire\Yelp\Exception\HttpException` that includes the response body, as a string, from the Yelp API. 93 | 94 | ```php 95 | $responseBody = $e->getResponseBody(); // string from Http request 96 | $responseBodyObject = json_decode($responseBody); 97 | ``` 98 | 99 | ### Advanced usage 100 | 101 | Both the [v3 client](API-GUIDE-v3.md) and the [v2 client](API-GUIDE-v2.md) expose some public methods that allow overiding default behavior by providing alternative HTTP clients and requests. 102 | 103 | ```php 104 | $client = new \Stevenmaguire\Yelp\v3\Client(array( 105 | 'accessToken' => $accessToken, 106 | )); 107 | 108 | // Create a new guzzle http client 109 | $specialHttpClient = new \GuzzleHttp\Client([ 110 | // ... some special configuration 111 | ]); 112 | 113 | // Update the yelp client with the new guzzle http client 114 | // then get business data 115 | $business = $client->setHttpClient($specialHttpClient) 116 | ->getBusiness('the-motel-bar-chicago'); 117 | 118 | // Create request for other yelp API resource not supported by yelp-php 119 | $request = $client->getRequest('GET', '/v3/some-future-endpoint'); 120 | 121 | // Send that request 122 | $response = $client->getResponse($request); 123 | 124 | // See the contents 125 | echo $response->getBody(); 126 | ``` 127 | 128 | ## Upgrading with Yelp API v2 support from `yelp-php 1.x` to `yelp-php 2.x` 129 | 130 | ```php 131 | // same options for all 132 | $options = array( 133 | 'consumerKey' => 'YOUR COSUMER KEY', 134 | 'consumerSecret' => 'YOUR CONSUMER SECRET', 135 | 'token' => 'YOUR TOKEN', 136 | 'tokenSecret' => 'YOUR TOKEN SECRET', 137 | 'apiHost' => 'api.yelp.com' // Optional, default 'api.yelp.com' 138 | ); 139 | 140 | 141 | // yelp-php 1.x 142 | $client = new Stevenmaguire\Yelp\Client($options); 143 | 144 | // yelp-php 2.x - option 1 145 | $client = \Stevenmaguire\Yelp\ClientFactory::makeWith( 146 | $options, 147 | \Stevenmaguire\Yelp\Version::TWO 148 | ); 149 | 150 | // yelp-php 2.x - option 2 151 | $client = new \Stevenmaguire\Yelp\v2\Client($options); 152 | ``` 153 | 154 | ## Testing 155 | 156 | ``` bash 157 | $ ./vendor/bin/phpunit 158 | ``` 159 | 160 | ## Contributing 161 | 162 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 163 | 164 | ## Credits 165 | 166 | - [Steven Maguire](https://github.com/stevenmaguire) 167 | - [All Contributors](https://github.com/stevenmaguire/yelp-php/contributors) 168 | 169 | ## License 170 | 171 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 172 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stevenmaguire/yelp-php", 3 | "description": "A php client for consuming Yelp API", 4 | "homepage" : "http://github.com/stevenmaguire/yelp-php", 5 | "authors" : [ 6 | { 7 | "name" : "Steven Maguire", 8 | "email" : "stevenmaguire@gmail.com", 9 | "homepage" : "http://stevenmaguire.com", 10 | "role" : "Developer" 11 | } 12 | ], 13 | "keywords": [ 14 | "api", 15 | "oauth1", 16 | "oauth2", 17 | "yelp", 18 | "php" 19 | ], 20 | "license": "MIT", 21 | "require": { 22 | "php": ">=5.6.0", 23 | "guzzlehttp/oauth-subscriber": "~0.3" 24 | }, 25 | "require-dev": { 26 | "eloquent/phony": "^0.14.1", 27 | "phpunit/phpunit": "~4.0", 28 | "squizlabs/php_codesniffer": "~2.0" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Stevenmaguire\\Yelp\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Stevenmaguire\\Yelp\\Test\\": "tests/src/" 38 | } 39 | }, 40 | "minimum-stability": "stable", 41 | "suggest": { 42 | "stevenmaguire/oauth2-yelp": "Provides functionality to obtain OAuth2 access tokens, needed to execute Yelp API v3 codepaths" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 20 | 22 | 23 | 24 | 25 | ./tests/ 26 | 27 | 28 | 29 | 30 | ./ 31 | 32 | ./vendor 33 | ./tests 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/ClientFactory.php: -------------------------------------------------------------------------------- 1 | responseBody = $body; 22 | 23 | return $this; 24 | } 25 | 26 | /** 27 | * Get exception response body 28 | * 29 | * @return string 30 | */ 31 | public function getResponseBody() 32 | { 33 | return $this->responseBody; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Exception/InvalidVersionException.php: -------------------------------------------------------------------------------- 1 | $property; 18 | } 19 | 20 | return null; 21 | } 22 | 23 | /** 24 | * Maps legacy configuration keys to updated keys. 25 | * 26 | * @param array $configuration 27 | * 28 | * @return array 29 | */ 30 | protected function mapConfiguration(array $configuration) 31 | { 32 | array_walk($configuration, function ($value, $key) use (&$configuration) { 33 | $newKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key)))); 34 | $configuration[$newKey] = $value; 35 | }); 36 | 37 | return $configuration; 38 | } 39 | 40 | /** 41 | * Parse configuration using defaults 42 | * 43 | * @param array $configuration 44 | * @param array $defaults 45 | * 46 | * @return mixed 47 | */ 48 | protected function parseConfiguration($configuration = [], $defaults = []) 49 | { 50 | $configuration = array_merge($defaults, $this->mapConfiguration($configuration)); 51 | 52 | array_walk($configuration, [$this, 'setConfig']); 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * Attempts to set a given value. 59 | * 60 | * @param mixed $value 61 | * @param string $key 62 | * 63 | * @return mixed 64 | */ 65 | protected function setConfig($value, $key) 66 | { 67 | $setter = 'set' . ucfirst($key); 68 | 69 | if (method_exists($this, $setter)) { 70 | $this->$setter($value); 71 | } elseif (property_exists($this, $key)) { 72 | $this->$key = $value; 73 | } 74 | 75 | return $this; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Tool/HttpTrait.php: -------------------------------------------------------------------------------- 1 | prepareQueryParams($parameters, $options); 51 | 52 | if ($queryString) { 53 | $uri = new Uri($url); 54 | $existingQuery = $uri->getQuery(); 55 | $updatedQuery = empty($existingQuery) ? $queryString : $existingQuery . '&' . $queryString; 56 | $url = (string) $uri->withQuery($updatedQuery); 57 | } 58 | 59 | return $url; 60 | } 61 | 62 | /** 63 | * Flattens given array into comma separated value. 64 | * 65 | * @param mixed $input 66 | * 67 | * @return string|mixed 68 | */ 69 | private function arrayToCsv($input) 70 | { 71 | if (is_array($input)) { 72 | $input = implode(',', $input); 73 | } 74 | 75 | return $input; 76 | } 77 | 78 | /** 79 | * Coerces given value into boolean and returns string representation 80 | * 81 | * @param boolean $value 82 | * 83 | * @return string 84 | */ 85 | private function getBoolString($value) 86 | { 87 | return (bool) $value ? 'true' : 'false'; 88 | } 89 | 90 | /** 91 | * Returns the yelp client's http client to the given http client. Client. 92 | * 93 | * @return GuzzleHttp\Client|null 94 | */ 95 | public function getHttpClient() 96 | { 97 | return $this->httpClient; 98 | } 99 | 100 | /** 101 | * Creates a PSR-7 Request instance. 102 | * 103 | * @param null|string $method HTTP method for the request. 104 | * @param null|string $uri URI for the request. 105 | * @param array $headers Headers for the message. 106 | * @param string|resource|StreamInterface $body Message body. 107 | * @param string $version HTTP protocol version. 108 | * 109 | * @return Request 110 | */ 111 | public function getRequest( 112 | $method, 113 | $uri, 114 | array $headers = [], 115 | $body = null, 116 | $version = '1.1' 117 | ) { 118 | $uri = new Uri($uri); 119 | 120 | if (!$uri->getHost()) { 121 | $uri = $uri->withHost($this->apiHost); 122 | } 123 | 124 | if (!$uri->getScheme()) { 125 | $uri = $uri->withScheme(($this->scheme ?: 'https')); 126 | } 127 | 128 | return new Request($method, $uri, $headers, $body, $version); 129 | } 130 | 131 | /** 132 | * Sends a request instance and returns a response instance. 133 | * 134 | * WARNING: This method does not attempt to catch exceptions caused by HTTP 135 | * errors! It is recommended to wrap this method in a try/catch block. 136 | * 137 | * @param RequestInterface $request 138 | * @return ResponseInterface 139 | * @throws Stevenmaguire\Yelp\Exception\HttpException 140 | */ 141 | public function getResponse(RequestInterface $request) 142 | { 143 | try { 144 | return $this->getHttpClient()->send($request); 145 | } catch (BadResponseException $e) { 146 | $exception = new HttpException($e->getMessage()); 147 | 148 | throw $exception->setResponseBody((string) $e->getResponse()->getBody()); 149 | } 150 | } 151 | 152 | /** 153 | * Provides a hook that handles the response before returning to the consumer. 154 | * 155 | * @param ResponseInterface $response 156 | * 157 | * @return ResponseInterface 158 | */ 159 | abstract protected function handleResponse(ResponseInterface $response); 160 | 161 | /** 162 | * Updates query params array to apply yelp specific formatting rules. 163 | * 164 | * @param array $params 165 | * @param string[] $csvParams 166 | * 167 | * @return string 168 | */ 169 | protected function prepareQueryParams($params = [], $csvParams = []) 170 | { 171 | array_walk($params, function ($value, $key) use (&$params, $csvParams) { 172 | if (is_bool($value)) { 173 | $params[$key] = $this->getBoolString($value); 174 | } 175 | 176 | if (in_array($key, $csvParams)) { 177 | $params[$key] = $this->arrayToCsv($value); 178 | } 179 | }); 180 | 181 | return http_build_query($params); 182 | } 183 | 184 | /** 185 | * Makes a request to the Yelp API and returns the response 186 | * 187 | * @param RequestInterface $request 188 | * 189 | * @return stdClass The JSON response from the request 190 | * @throws Stevenmaguire\Yelp\Exception\ClientConfigurationException 191 | * @throws Stevenmaguire\Yelp\Exception\HttpException 192 | */ 193 | protected function processRequest(RequestInterface $request) 194 | { 195 | $response = $this->handleResponse($this->getResponse($request)); 196 | 197 | return json_decode($response->getBody()); 198 | } 199 | 200 | /** 201 | * Updates the yelp client's http client to the given http client. Client. 202 | * 203 | * @param HttpClient $client 204 | * 205 | * @return mixed 206 | */ 207 | public function setHttpClient(HttpClient $client) 208 | { 209 | $this->httpClient = $client; 210 | 211 | return $this; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/Version.php: -------------------------------------------------------------------------------- 1 | null, 79 | 'consumerSecret' => null, 80 | 'token' => null, 81 | 'tokenSecret' => null, 82 | 'apiHost' => 'api.yelp.com', 83 | // 'scheme' => 'http' 84 | ); 85 | 86 | $this->parseConfiguration($options, $defaults); 87 | 88 | if (!$this->getHttpClient()) { 89 | $this->setHttpClient($this->createDefaultHttpClient()); 90 | } 91 | } 92 | 93 | /** 94 | * Creates default http client with appropriate authorization configuration. 95 | * 96 | * @return HttpClient 97 | */ 98 | public function createDefaultHttpClient() 99 | { 100 | $stack = HandlerStack::create(); 101 | 102 | $middleware = new Oauth1([ 103 | 'consumer_key' => $this->consumerKey, 104 | 'consumer_secret' => $this->consumerSecret, 105 | 'token' => $this->token, 106 | 'token_secret' => $this->tokenSecret 107 | ]); 108 | 109 | $stack->push($middleware); 110 | 111 | return new HttpClient([ 112 | 'handler' => $stack 113 | ]); 114 | } 115 | 116 | /** 117 | * Fetches a specific business by id. 118 | * 119 | * @param string $businessId 120 | * @param array $parameters 121 | * 122 | * @return stdClass 123 | * @throws Stevenmaguire\Yelp\Exception\HttpException 124 | */ 125 | public function getBusiness($businessId, $parameters = []) 126 | { 127 | $path = $this->appendParametersToUrl('/v2/business/'.$businessId, $parameters); 128 | $request = $this->getRequest('GET', $path); 129 | 130 | return $this->processRequest($request); 131 | } 132 | 133 | /** 134 | * Sends a request instance and returns a response instance. 135 | * 136 | * WARNING: This method does not attempt to catch exceptions caused by HTTP 137 | * errors! It is recommended to wrap this method in a try/catch block. 138 | * 139 | * @param RequestInterface $request 140 | * @return ResponseInterface 141 | * @throws Stevenmaguire\Yelp\Exception\HttpException 142 | */ 143 | public function getResponse(RequestInterface $request) 144 | { 145 | try { 146 | return $this->getHttpClient()->get((string) $request->getUri(), ['auth' => 'oauth']); 147 | } catch (BadResponseException $e) { 148 | $exception = new HttpException($e->getMessage()); 149 | 150 | throw $exception->setResponseBody((string) $e->getResponse()->getBody()); 151 | } 152 | } 153 | 154 | /** 155 | * Provides a hook that handles the response before returning to the consumer. 156 | * 157 | * @param ResponseInterface $response 158 | * 159 | * @return ResponseInterface 160 | */ 161 | protected function handleResponse(ResponseInterface $response) 162 | { 163 | return $response; 164 | } 165 | 166 | /** 167 | * Fetches results from the Business Search API. 168 | * 169 | * @param array $parameters 170 | * 171 | * @return stdClass 172 | * @throws Stevenmaguire\Yelp\Exception\HttpException 173 | */ 174 | public function search($parameters = []) 175 | { 176 | $parameters = array_merge([ 177 | 'term' => $this->defaultTerm, 178 | 'location' => $this->defaultLocation, 179 | 'limit' => $this->searchLimit 180 | ], $parameters); 181 | 182 | $path = $this->appendParametersToUrl('/v2/search', $parameters); 183 | $request = $this->getRequest('GET', $path); 184 | 185 | return $this->processRequest($request); 186 | } 187 | 188 | /** 189 | * Fetches results from the Business Search API by Phone. 190 | * 191 | * @param array $parameters 192 | * 193 | * @return stdClass 194 | * @throws Stevenmaguire\Yelp\Exception\HttpException 195 | */ 196 | public function searchByPhone($parameters = []) 197 | { 198 | $path = $this->appendParametersToUrl('/v2/phone_search', $parameters); 199 | $request = $this->getRequest('GET', $path); 200 | 201 | return $this->processRequest($request); 202 | } 203 | 204 | /** 205 | * Set default location 206 | * 207 | * @param string $location 208 | * 209 | * @return Client 210 | */ 211 | public function setDefaultLocation($location) 212 | { 213 | $this->defaultLocation = $location; 214 | 215 | return $this; 216 | } 217 | 218 | /** 219 | * Set default term 220 | * 221 | * @param string $term 222 | * 223 | * @return Client 224 | */ 225 | public function setDefaultTerm($term) 226 | { 227 | $this->defaultTerm = $term; 228 | 229 | return $this; 230 | } 231 | 232 | /** 233 | * Set search limit 234 | * 235 | * @param integer $limit 236 | * 237 | * @return Client 238 | */ 239 | public function setSearchLimit($limit) 240 | { 241 | if (is_int($limit)) { 242 | $this->searchLimit = $limit; 243 | } 244 | 245 | return $this; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /src/v3/Client.php: -------------------------------------------------------------------------------- 1 | null, 46 | 'apiHost' => 'api.yelp.com', 47 | 'apiKey' => null, 48 | ]; 49 | 50 | $this->parseConfiguration($options, $defaults); 51 | 52 | if (!$this->getHttpClient()) { 53 | $this->setHttpClient($this->createDefaultHttpClient()); 54 | } 55 | } 56 | 57 | /** 58 | * Creates default http client with appropriate authorization configuration. 59 | * 60 | * @return \GuzzleHttp\Client 61 | */ 62 | public function createDefaultHttpClient() 63 | { 64 | return new HttpClient([ 65 | 'headers' => $this->getDefaultHeaders() 66 | ]); 67 | } 68 | 69 | /** 70 | * Fetches results from the Autocomplete API. 71 | * 72 | * @param array $parameters 73 | * 74 | * @return stdClass 75 | * @throws Stevenmaguire\Yelp\Exception\HttpException 76 | * @link https://www.yelp.com/developers/documentation/v3/autocomplete 77 | */ 78 | public function getAutocompleteResults($parameters = []) 79 | { 80 | $path = $this->appendParametersToUrl('/v3/autocomplete', $parameters); 81 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 82 | 83 | return $this->processRequest($request); 84 | } 85 | 86 | /** 87 | * Returns the api key, if available, otherwise returns access token. 88 | * 89 | * @return string|null 90 | * @link https://www.yelp.com/developers/documentation/v3/authentication#where-is-my-client-secret-going 91 | */ 92 | private function getBearerToken() 93 | { 94 | if ($this->apiKey) { 95 | return $this->apiKey; 96 | } 97 | 98 | return $this->accessToken; 99 | } 100 | 101 | /** 102 | * Fetches a specific business by id. 103 | * 104 | * @param string $businessId 105 | * @param array $parameters 106 | * 107 | * @return stdClass 108 | * @throws Stevenmaguire\Yelp\Exception\HttpException 109 | * @link https://www.yelp.com/developers/documentation/v3/business 110 | */ 111 | public function getBusiness($businessId, $parameters = []) 112 | { 113 | $path = $this->appendParametersToUrl('/v3/businesses/'.$businessId, $parameters); 114 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 115 | 116 | return $this->processRequest($request); 117 | } 118 | 119 | /** 120 | * Fetches reviews for a specific business by id. 121 | * 122 | * @param string $businessId 123 | * @param array $parameters 124 | * 125 | * @return stdClass 126 | * @throws Stevenmaguire\Yelp\Exception\HttpException 127 | * @link https://www.yelp.com/developers/documentation/v3/business_reviews 128 | */ 129 | public function getBusinessReviews($businessId, $parameters = []) 130 | { 131 | $path = $this->appendParametersToUrl('/v3/businesses/'.$businessId.'/reviews', $parameters); 132 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 133 | 134 | return $this->processRequest($request); 135 | } 136 | 137 | /** 138 | * Fetches results from the Business Search API. 139 | * 140 | * @param array $parameters 141 | * 142 | * @return stdClass 143 | * @throws Stevenmaguire\Yelp\Exception\HttpException 144 | * @link https://www.yelp.com/developers/documentation/v3/business_search 145 | */ 146 | public function getBusinessesSearchResults($parameters = []) 147 | { 148 | $csvParams = ['attributes', 'categories', 'price']; 149 | 150 | $path = $this->appendParametersToUrl('/v3/businesses/search', $parameters, $csvParams); 151 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 152 | 153 | return $this->processRequest($request); 154 | } 155 | 156 | /** 157 | * Fetches results from the Business Search API by Phone. 158 | * 159 | * @param string $phoneNumber 160 | * 161 | * @return stdClass 162 | * @throws Stevenmaguire\Yelp\Exception\HttpException 163 | * @link https://www.yelp.com/developers/documentation/v3/business_search_phone 164 | */ 165 | public function getBusinessesSearchResultsByPhone($phoneNumber) 166 | { 167 | $parameters = [ 168 | 'phone' => $phoneNumber 169 | ]; 170 | 171 | $path = $this->appendParametersToUrl('/v3/businesses/search/phone', $parameters); 172 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 173 | 174 | return $this->processRequest($request); 175 | } 176 | 177 | /** 178 | * Builds and returns default headers, specifically including the Authorization 179 | * header used for authenticating HTTP requests to Yelp. 180 | * 181 | * @return array 182 | */ 183 | protected function getDefaultHeaders() 184 | { 185 | return [ 186 | 'Authorization' => 'Bearer ' . $this->getBearerToken(), 187 | ]; 188 | } 189 | 190 | /** 191 | * Returns the latest rate limit metrics, absorbed from the HTTP headers of 192 | * the most recent HTTP request to the Yelp v3 service. 193 | * 194 | * @return RateLimit|null 195 | * 196 | * @see https://www.yelp.com/developers/documentation/v3/rate_limiting 197 | */ 198 | public function getRateLimit() 199 | { 200 | return $this->rateLimit; 201 | } 202 | 203 | /** 204 | * Fetches results from the Business Search API by Type. 205 | * 206 | * @param string $type 207 | * @param array $parameters 208 | * 209 | * @return stdClass 210 | * @throws Stevenmaguire\Yelp\Exception\HttpException 211 | * @link https://www.yelp.com/developers/documentation/v3/transactions_search 212 | */ 213 | public function getTransactionsSearchResultsByType($type, $parameters = []) 214 | { 215 | $path = $this->appendParametersToUrl('/v3/transactions/'.$type.'/search', $parameters); 216 | $request = $this->getRequest('GET', $path, $this->getDefaultHeaders()); 217 | 218 | return $this->processRequest($request); 219 | } 220 | 221 | /** 222 | * Provides a hook that handles the response before returning to the consumer. 223 | * 224 | * @param ResponseInterface $response 225 | * 226 | * @return ResponseInterface 227 | */ 228 | protected function handleResponse(ResponseInterface $response) 229 | { 230 | $this->rateLimit = new RateLimit; 231 | $this->rateLimit->dailyLimit = (integer) $response->getHeaderLine('RateLimit-DailyLimit'); 232 | $this->rateLimit->remaining = (integer) $response->getHeaderLine('RateLimit-Remaining'); 233 | $this->rateLimit->resetTime = $response->getHeaderLine('RateLimit-ResetTime'); 234 | 235 | return $response; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/v3/RateLimit.php: -------------------------------------------------------------------------------- 1 | createdAt = (string) date('c'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/ClientFactoryTest.php: -------------------------------------------------------------------------------- 1 | 'bar' 16 | ]; 17 | 18 | $client = ClientFactory::makeWith($options); 19 | 20 | $this->assertInstanceOf(VersionTwoClient::class, $client); 21 | } 22 | 23 | public function testVersionTwoClientCreatedWhenVersionTwoProvided() 24 | { 25 | $options = [ 26 | 'foo' => 'bar' 27 | ]; 28 | 29 | $client = ClientFactory::makeWith($options, Version::TWO); 30 | 31 | $this->assertInstanceOf(VersionTwoClient::class, $client); 32 | } 33 | 34 | public function testVersionThreeClientCreatedWhenVersionThreeProvided() 35 | { 36 | $options = [ 37 | 'foo' => 'bar' 38 | ]; 39 | 40 | $client = ClientFactory::makeWith($options, Version::THREE); 41 | 42 | $this->assertInstanceOf(VersionThreeClient::class, $client); 43 | } 44 | 45 | /** 46 | * @expectedException Stevenmaguire\Yelp\Exception\InvalidVersionException 47 | */ 48 | public function testExceptionThrownWhenInvalidVersionProvided() 49 | { 50 | $options = [ 51 | 'foo' => 'bar' 52 | ]; 53 | 54 | $client = ClientFactory::makeWith($options, 'foo'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/Tool/HttpTraitTest.php: -------------------------------------------------------------------------------- 1 | apiHost = 'foo'; 27 | 28 | $request = $this->getRequest('get', '/bar'); 29 | 30 | $this->assertContains('foo/bar', (string) $request->getUri()); 31 | } 32 | 33 | public function testGetRequestAddsSchemeWhenNotProvided() 34 | { 35 | $this->apiHost = 'foo'; 36 | 37 | $request = $this->getRequest('get', '/bar'); 38 | 39 | $this->assertContains('https://foo/bar', (string) $request->getUri()); 40 | } 41 | 42 | public function testAppendingParametersToUrl() 43 | { 44 | $url = '/foo/bar'; 45 | $parameters = []; 46 | $result = $this->appendParametersToUrl($url, $parameters); 47 | $this->assertEquals($url, $result); 48 | 49 | $url = '/foo/bar'; 50 | $parameters = ['foo' => 'bar']; 51 | $result = $this->appendParametersToUrl($url, $parameters); 52 | $this->assertEquals($url . '?foo=bar', $result); 53 | 54 | $url = '/foo/bar?'; 55 | $parameters = ['foo' => 'bar']; 56 | $result = $this->appendParametersToUrl($url, $parameters); 57 | $this->assertEquals($url . 'foo=bar', $result); 58 | 59 | $url = '/foo/bar?foo=bar'; 60 | $parameters = ['foo2' => 'bar2']; 61 | $result = $this->appendParametersToUrl($url, $parameters); 62 | $this->assertEquals($url . '&foo2=bar2', $result); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tests/v2/ClientTest.php: -------------------------------------------------------------------------------- 1 | client = new Yelp([ 23 | 'consumerKey' => 'consumer_key', 24 | 'consumerSecret' => 'consumer_secret', 25 | 'token' => 'access_token', 26 | 'tokenSecret' => 'token_secret', 27 | 'apiHost' => 'api.yelp.com' 28 | ]); 29 | } 30 | 31 | protected function getResponseJson($type) 32 | { 33 | return file_get_contents(__DIR__.'/'.$type.'_response.json'); 34 | } 35 | 36 | public function testConfigurationMapper() 37 | { 38 | $config = [ 39 | 'consumer_key' => uniqid(), 40 | 'consumer_secret' => uniqid(), 41 | 'token' => uniqid(), 42 | 'token_secret' => uniqid(), 43 | 'api_host' => uniqid() 44 | ]; 45 | 46 | $client = new Yelp($config); 47 | 48 | $this->assertEquals($config['consumer_key'], $client->consumerKey); 49 | $this->assertEquals($config['consumer_secret'], $client->consumerSecret); 50 | $this->assertEquals($config['token'], $client->token); 51 | $this->assertEquals($config['token_secret'], $client->tokenSecret); 52 | $this->assertEquals($config['api_host'], $client->apiHost); 53 | $this->assertNull($client->{uniqid()}); 54 | } 55 | 56 | public function testGetBusiness() 57 | { 58 | $businessId = 'foo'; 59 | $path = '/v2/business/'.$businessId; 60 | $payload = $this->getResponseJson('business'); 61 | 62 | $parameters = [ 63 | 'actionLinks' => true 64 | ]; 65 | 66 | $stream = Phony::mock(StreamInterface::class); 67 | $stream->__toString->returns($payload); 68 | 69 | $response = Phony::mock(ResponseInterface::class); 70 | $response->getBody->returns($stream->get()); 71 | 72 | $httpClient = Phony::mock(HttpClient::class); 73 | $httpClient->get->returns($response->get()); 74 | 75 | $results = $this->client->setHttpClient($httpClient->get()) 76 | ->getBusiness($businessId, $parameters); 77 | 78 | $this->assertEquals(json_decode($payload), $results); 79 | 80 | Phony::inOrder( 81 | $httpClient->get->calledWith( 82 | $this->callback(function ($url) use ($path, $parameters) { 83 | $parameters['actionLinks'] = 'true'; 84 | $queryString = http_build_query($parameters); 85 | return strpos($url, $path) !== false 86 | && ($queryString && strpos($url, $queryString) !== false); 87 | }), 88 | $this->callback(function ($config) { 89 | return $config == ['auth' => 'oauth']; 90 | }) 91 | ), 92 | $response->getBody->called(), 93 | $stream->__toString->called() 94 | ); 95 | } 96 | 97 | public function testGetBusinessesSearchResults() 98 | { 99 | $path = '/v2/search'; 100 | $payload = $this->getResponseJson('search'); 101 | 102 | $term = 'bars'; 103 | $location = 'Chicago, IL'; 104 | $parameters = [ 105 | 'term' => $term, 106 | 'location' => $location 107 | ]; 108 | 109 | $stream = Phony::mock(StreamInterface::class); 110 | $stream->__toString->returns($payload); 111 | 112 | $response = Phony::mock(ResponseInterface::class); 113 | $response->getBody->returns($stream->get()); 114 | 115 | $httpClient = Phony::mock(HttpClient::class); 116 | $httpClient->get->returns($response->get()); 117 | 118 | $results = $this->client->setHttpClient($httpClient->get()) 119 | ->search($parameters); 120 | 121 | $this->assertEquals(json_decode($payload), $results); 122 | 123 | Phony::inOrder( 124 | $httpClient->get->calledWith( 125 | $this->callback(function ($url) use ($path, $parameters) { 126 | $queryString = http_build_query($parameters); 127 | return strpos($url, $path) !== false 128 | && ($queryString && strpos($url, $queryString) !== false); 129 | }), 130 | $this->callback(function ($config) { 131 | return $config == ['auth' => 'oauth']; 132 | }) 133 | ), 134 | $response->getBody->called(), 135 | $stream->__toString->called() 136 | ); 137 | } 138 | 139 | public function testItCanSetSearchDefaults() 140 | { 141 | $defaults = [ 142 | 'term' => 'stores', 143 | 'location' => 'Chicago, IL', 144 | 'limit' => 10 145 | ]; 146 | 147 | // new here 148 | $path = '/v2/search'; 149 | $payload = $this->getResponseJson('search'); 150 | 151 | $term = 'bars'; 152 | $location = 'Chicago, IL'; 153 | 154 | $stream = Phony::mock(StreamInterface::class); 155 | $stream->__toString->returns($payload); 156 | 157 | $response = Phony::mock(ResponseInterface::class); 158 | $response->getBody->returns($stream->get()); 159 | 160 | $httpClient = Phony::mock(HttpClient::class); 161 | $httpClient->get->returns($response->get()); 162 | 163 | $results = $this->client->setDefaultLocation($defaults['location']) 164 | ->setDefaultTerm($defaults['term']) 165 | ->setSearchLimit($defaults['limit']) 166 | ->setHttpClient($httpClient->get()) 167 | ->search(); 168 | 169 | $this->assertEquals(json_decode($payload), $results); 170 | 171 | Phony::inOrder( 172 | $httpClient->get->calledWith( 173 | $this->callback(function ($url) use ($path, $defaults) { 174 | $queryString = http_build_query($defaults); 175 | return strpos($url, $path) !== false 176 | && ($queryString && strpos($url, $queryString) !== false); 177 | }), 178 | $this->callback(function ($config) { 179 | return $config == ['auth' => 'oauth']; 180 | }) 181 | ), 182 | $response->getBody->called(), 183 | $stream->__toString->called() 184 | ); 185 | } 186 | 187 | public function testGetBusinessesSearchResultsByPhone() 188 | { 189 | $phone = 'foo-bar'; 190 | $path = '/v2/phone_search'; 191 | $payload = $this->getResponseJson('search'); 192 | 193 | $parameters = [ 194 | 'phone' => $phone 195 | ]; 196 | 197 | $stream = Phony::mock(StreamInterface::class); 198 | $stream->__toString->returns($payload); 199 | 200 | $response = Phony::mock(ResponseInterface::class); 201 | $response->getBody->returns($stream->get()); 202 | 203 | $httpClient = Phony::mock(HttpClient::class); 204 | $httpClient->get->returns($response->get()); 205 | 206 | $results = $this->client->setHttpClient($httpClient->get()) 207 | ->searchByPhone($parameters); 208 | 209 | $this->assertEquals(json_decode($payload), $results); 210 | 211 | Phony::inOrder( 212 | $httpClient->get->calledWith( 213 | $this->callback(function ($url) use ($path, $parameters) { 214 | $queryString = http_build_query($parameters); 215 | return strpos($url, $path) !== false 216 | && ($queryString && strpos($url, $queryString) !== false); 217 | }), 218 | $this->callback(function ($config) { 219 | return $config == ['auth' => 'oauth']; 220 | }) 221 | ), 222 | $response->getBody->called(), 223 | $stream->__toString->called() 224 | ); 225 | } 226 | 227 | /** 228 | * @expectedException Stevenmaguire\Yelp\Exception\HttpException 229 | */ 230 | public function testClientRaisesExceptionWhenHttpRequestFails() 231 | { 232 | $businessId = 'foo'; 233 | $path = '/v2/businesses/'.$businessId; 234 | $payload = $this->getResponseJson('error'); 235 | 236 | $stream = Phony::mock(StreamInterface::class); 237 | $stream->__toString->returns($payload); 238 | 239 | $response = Phony::mock(ResponseInterface::class); 240 | $response->getBody->returns($stream->get()); 241 | 242 | $request = Phony::mock(RequestInterface::class); 243 | 244 | $httpClient = Phony::mock(HttpClient::class); 245 | $httpClient->get->throws(new BadResponseException( 246 | 'test exception', 247 | $request->get(), 248 | $response->get() 249 | )); 250 | 251 | try { 252 | $business = $this->client->setHttpClient($httpClient->get()) 253 | ->getBusiness($businessId); 254 | } catch (\Stevenmaguire\Yelp\Exception\HttpException $e) { 255 | $this->assertEquals($payload, $e->getResponseBody()); 256 | throw $e; 257 | } 258 | 259 | Phony::inOrder( 260 | $httpClient->get->calledWith( 261 | $this->callback(function ($url) use ($path) { 262 | return strpos($url, $path) !== false; 263 | }), 264 | $this->callback(function ($config) { 265 | return $config == ['auth' => 'oauth']; 266 | }) 267 | ), 268 | $response->getBody->called(), 269 | $stream->__toString->called() 270 | ); 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /tests/v2/business_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "categories": [ 3 | [ 4 | "Indian", 5 | "indpak" 6 | ], 7 | [ 8 | "Himalayan/Nepalese", 9 | "himalayan" 10 | ] 11 | ], 12 | "deals": [ 13 | { 14 | "currency_code": "USD", 15 | "image_url": "http://s3-media4.ak.yelpcdn.com/dphoto/ShQGf5qi-52HwPiKyZTZ3w/m.jpg", 16 | "options": [ 17 | { 18 | "formatted_original_price": "$20", 19 | "formatted_price": "$10", 20 | "is_quantity_limited": true, 21 | "original_price": 2000, 22 | "price": 1000, 23 | "purchase_url": "http://www.yelp.com/deal/cC24ccQGIH8mowfu5Vbe0Q/view", 24 | "remaining_count": 36, 25 | "title": "$10 for $20 voucher" 26 | } 27 | ], 28 | "url": "http://www.yelp.com/biz/urban-curry-san-francisco?deal=1", 29 | "is_popular": true, 30 | "time_start": 1317414369, 31 | "title": "$10 for $20 voucher" 32 | } 33 | ], 34 | "display_phone": "+1-415-677-9743", 35 | "eat24_url": "http://e24.io/r/5769?utm_campaign=public&utm_medium=yelpapi&utm_source=yelpapi", 36 | "gift_certificates": [ 37 | { 38 | "currency_code": "USD", 39 | "image_url": "http://s3-media4.ak.yelpcdn.com/bphoto/Hv5vsWpqeaUKepr9nffJnw/m.jpg", 40 | "options": [ 41 | { 42 | "formatted_price": "$25", 43 | "price": 2500 44 | }, 45 | { 46 | "formatted_price": "$50", 47 | "price": 5000 48 | } 49 | ], 50 | "url": "http://www.yelp.com/gift-certificates/some-donut-place-pasadena", 51 | "id": "ZZy5EwrI3wyHw8y54jZruA", 52 | "unused_balances": "CREDIT" 53 | } 54 | ], 55 | "id": "urban-curry-san-francisco", 56 | "image_url": "http://s3-media1.fl.yelpcdn.com/bphoto/u5b1u7c04C1GkptUg0grdA/ms.jpg", 57 | "is_claimed": true, 58 | "is_closed": false, 59 | "location": { 60 | "address": [ 61 | "523 Broadway" 62 | ], 63 | "city": "San Francisco", 64 | "coordinate": { 65 | "latitude": 37.7978994, 66 | "longitude": -122.4059649 67 | }, 68 | "country_code": "US", 69 | "cross_streets": "Romolo Pl & Kearny St", 70 | "display_address": [ 71 | "523 Broadway", 72 | "North Beach/Telegraph Hill", 73 | "San Francisco, CA 94133" 74 | ], 75 | "geo_accuracy": 9.5, 76 | "neighborhoods": [ 77 | "North Beach/Telegraph Hill", 78 | "Chinatown" 79 | ], 80 | "postal_code": "94133", 81 | "state_code": "CA" 82 | }, 83 | "menu_date_updated": 1443040751, 84 | "menu_provider": "single_platform", 85 | "mobile_url": "http://m.yelp.com/biz/urban-curry-san-francisco", 86 | "name": "Urban Curry", 87 | "phone": "4156779743", 88 | "rating": 4.0, 89 | "rating_img_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 90 | "rating_img_url_large": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 91 | "rating_img_url_small": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 92 | "review_count": 455, 93 | "reviews": [ 94 | { 95 | "excerpt": "One of the owners is a former Sherpa from Nepal who has summitted Mt. Everest twice. While the restaurant is in a seeder part of the City, it's also on one...", 96 | "id": "flAK8Mu4auUdcFNR7iPa6Q", 97 | "rating": 4, 98 | "rating_image_large_url": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png", 99 | "rating_image_small_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/f62a5be2f902/ico/stars/v1/stars_small_4.png", 100 | "rating_image_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c2f3dd9799a5/ico/stars/v1/stars_4.png", 101 | "time_created": 1440895245, 102 | "user": { 103 | "id": "3KNNxsQa4uooK5FAj7bVaQ", 104 | "image_url": "http://s3-media3.fl.yelpcdn.com/photo/hk31BkJvJ8qcqoUvZ38rmQ/ms.jpg", 105 | "name": "Hilary C." 106 | } 107 | } 108 | ], 109 | "snippet_image_url": "http://s3-media3.fl.yelpcdn.com/photo/hk31BkJvJ8qcqoUvZ38rmQ/ms.jpg", 110 | "snippet_text": "One of the owners is a former Sherpa from Nepal who has summitted Mt. Everest twice. While the restaurant is in a seeder part of the City, it's also on one...", 111 | "url": "http://www.yelp.com/biz/urban-curry-san-francisco" 112 | } 113 | -------------------------------------------------------------------------------- /tests/v2/error_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "text": "Invalid parameter", 4 | "id": "INVALID_PARAMETER", 5 | "field": "location" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/v2/search_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "businesses": [ 3 | { 4 | "categories": [ 5 | [ 6 | "Local Flavor", 7 | "localflavor" 8 | ], 9 | [ 10 | "Mass Media", 11 | "massmedia" 12 | ] 13 | ], 14 | "display_phone": "+1-415-908-3801", 15 | "id": "yelp-san-francisco", 16 | "image_url": "http://s3-media3.fl.yelpcdn.com/bphoto/nQK-6_vZMt5n88zsAS94ew/ms.jpg", 17 | "is_claimed": true, 18 | "is_closed": false, 19 | "location": { 20 | "address": [ 21 | "140 New Montgomery St" 22 | ], 23 | "city": "San Francisco", 24 | "coordinate": { 25 | "latitude": 37.7867703362929, 26 | "longitude": -122.399958372115 27 | }, 28 | "country_code": "US", 29 | "cross_streets": "Natoma St & Minna St", 30 | "display_address": [ 31 | "140 New Montgomery St", 32 | "Financial District", 33 | "San Francisco, CA 94105" 34 | ], 35 | "geo_accuracy": 9.5, 36 | "neighborhoods": [ 37 | "Financial District", 38 | "SoMa" 39 | ], 40 | "postal_code": "94105", 41 | "state_code": "CA" 42 | }, 43 | "mobile_url": "http://m.yelp.com/biz/yelp-san-francisco", 44 | "name": "Yelp", 45 | "phone": "4159083801", 46 | "rating": 2.5, 47 | "rating_img_url": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/c7fb9aff59f9/ico/stars/v1/stars_2_half.png", 48 | "rating_img_url_large": "http://s3-media2.fl.yelpcdn.com/assets/2/www/img/d63e3add9901/ico/stars/v1/stars_large_2_half.png", 49 | "rating_img_url_small": "http://s3-media4.fl.yelpcdn.com/assets/2/www/img/8e8633e5f8f0/ico/stars/v1/stars_small_2_half.png", 50 | "review_count": 7140, 51 | "snippet_image_url": "http://s3-media4.fl.yelpcdn.com/photo/YcjPScwVxF05kj6zt10Fxw/ms.jpg", 52 | "snippet_text": "What would I do without Yelp?\n\nI wouldn't be HALF the foodie I've become it weren't for this business. \n\nYelp makes it virtually effortless to discover new...", 53 | "url": "http://www.yelp.com/biz/yelp-san-francisco" 54 | } 55 | ], 56 | "total": 2316 57 | } 58 | -------------------------------------------------------------------------------- /tests/v3/ClientTest.php: -------------------------------------------------------------------------------- 1 | client = new Yelp([ 21 | 'accessToken' => 'mock_access_token', 22 | 'apiHost' => 'api.yelp.com', 23 | 'apiKey' => 'mock_api_key', 24 | ]); 25 | } 26 | 27 | protected function getResponseJson($type) 28 | { 29 | return file_get_contents(__DIR__.'/'.$type.'_response.json'); 30 | } 31 | 32 | public function testConfigurationMapper() 33 | { 34 | $config = [ 35 | 'accessToken' => uniqid(), 36 | 'apiHost' => uniqid(), 37 | 'apiKey' => uniqid() 38 | ]; 39 | 40 | $client = new Yelp($config); 41 | $this->assertEquals($config['accessToken'], $client->accessToken); 42 | $this->assertEquals($config['apiHost'], $client->apiHost); 43 | $this->assertEquals($config['apiKey'], $client->apiKey); 44 | $this->assertNull($client->{uniqid()}); 45 | } 46 | 47 | public function testClientCanBeConfiguredWithHttpClient() 48 | { 49 | $httpClient = Phony::mock(HttpClient::class)->get(); 50 | 51 | $client = new Yelp([ 52 | 'accessToken' => 'mock_access_token', 53 | 'apiHost' => 'api.yelp.com', 54 | 'apiKey' => 'mock_api_key', 55 | 'httpClient' => $httpClient 56 | ]); 57 | 58 | $this->assertEquals($httpClient, $client->getHttpClient()); 59 | } 60 | 61 | public function testDefaultClientIncludesAccessToken() 62 | { 63 | $client = new Yelp([ 64 | 'accessToken' => 'mock_access_token', 65 | 'apiHost' => 'api.yelp.com' 66 | ]); 67 | 68 | $this->assertContains( 69 | 'mock_access_token', 70 | $client->getHttpClient()->getConfig()['headers']['Authorization'] 71 | ); 72 | } 73 | 74 | public function testDefaultClientIncludesApiKey() 75 | { 76 | $client = new Yelp([ 77 | 'apiHost' => 'api.yelp.com', 78 | 'apiKey' => 'mock_api_key', 79 | ]); 80 | 81 | $this->assertContains( 82 | 'mock_api_key', 83 | $client->getHttpClient()->getConfig()['headers']['Authorization'] 84 | ); 85 | } 86 | 87 | public function testApiKeyIsPreferredOverAccessToken() 88 | { 89 | $client = new Yelp([ 90 | 'accessToken' => 'mock_access_token', 91 | 'apiHost' => 'api.yelp.com', 92 | 'apiKey' => 'mock_api_key', 93 | ]); 94 | 95 | $this->assertContains( 96 | 'mock_api_key', 97 | $client->getHttpClient()->getConfig()['headers']['Authorization'] 98 | ); 99 | } 100 | 101 | public function testGetAutocompleteResults() 102 | { 103 | $path = '/v3/autocomplete'; 104 | $payload = $this->getResponseJson('autocomplete'); 105 | 106 | $parameters = [ 107 | 'text' => 'foo', 108 | 'latitude' => 1.0000, 109 | 'longitude' => 1.0000, 110 | 'locale' => 'bar' 111 | ]; 112 | 113 | $stream = Phony::mock(StreamInterface::class); 114 | $stream->__toString->returns($payload); 115 | 116 | $response = Phony::mock(ResponseInterface::class); 117 | $response->getBody->returns($stream->get()); 118 | 119 | $httpClient = Phony::mock(HttpClient::class); 120 | $httpClient->send->returns($response->get()); 121 | 122 | $results = $this->client->setHttpClient($httpClient->get()) 123 | ->getAutocompleteResults($parameters); 124 | 125 | $this->assertEquals(json_decode($payload), $results); 126 | 127 | Phony::inOrder( 128 | $httpClient->send->calledWith( 129 | $this->callback(function ($request) use ($path, $parameters) { 130 | $queryString = http_build_query($parameters); 131 | return $request->getMethod() === 'GET' 132 | && strpos((string) $request->getUri(), $path) !== false 133 | && ($queryString && strpos((string) $request->getUri(), $queryString) !== false); 134 | }) 135 | ), 136 | $response->getBody->called(), 137 | $stream->__toString->called() 138 | ); 139 | } 140 | 141 | public function testGetBusiness() 142 | { 143 | $businessId = 'foo'; 144 | $path = '/v3/businesses/'.$businessId; 145 | $payload = $this->getResponseJson('business'); 146 | $dailyLimit = rand(); 147 | $remaining = rand(); 148 | $resetTime = uniqid(); 149 | 150 | $parameters = [ 151 | 'locale' => 'bar' 152 | ]; 153 | 154 | $stream = Phony::mock(StreamInterface::class); 155 | $stream->__toString->returns($payload); 156 | 157 | $response = Phony::mock(ResponseInterface::class); 158 | 159 | $response->getBody->returns($stream->get()); 160 | $response->getHeaderLine->with('RateLimit-DailyLimit')->returns($dailyLimit); 161 | $response->getHeaderLine->with('RateLimit-Remaining')->returns($remaining); 162 | $response->getHeaderLine->with('RateLimit-ResetTime')->returns($resetTime); 163 | 164 | $httpClient = Phony::mock(HttpClient::class); 165 | $httpClient->send->returns($response->get()); 166 | 167 | $results = $this->client->setHttpClient($httpClient->get()) 168 | ->getBusiness($businessId, $parameters); 169 | 170 | $this->assertEquals(json_decode($payload), $results); 171 | 172 | Phony::inOrder( 173 | $httpClient->send->calledWith( 174 | $this->callback(function ($request) use ($path, $parameters) { 175 | $queryString = http_build_query($parameters); 176 | return $request->getMethod() === 'GET' 177 | && strpos((string) $request->getUri(), $path) !== false 178 | && ($queryString && strpos((string) $request->getUri(), $queryString) !== false); 179 | }) 180 | ), 181 | $response->getHeaderLine->calledWith('RateLimit-DailyLimit'), 182 | $response->getHeaderLine->calledWith('RateLimit-Remaining'), 183 | $response->getHeaderLine->calledWith('RateLimit-ResetTime'), 184 | $response->getBody->called(), 185 | $stream->__toString->called() 186 | ); 187 | 188 | $this->assertEquals($dailyLimit, $this->client->getRateLimit()->dailyLimit); 189 | $this->assertEquals($remaining, $this->client->getRateLimit()->remaining); 190 | $this->assertEquals($resetTime, $this->client->getRateLimit()->resetTime); 191 | } 192 | 193 | public function testGetBusinessReviews() 194 | { 195 | $businessId = 'foo'; 196 | $path = '/v3/businesses/'.$businessId.'/reviews'; 197 | $payload = $this->getResponseJson('business_reviews'); 198 | $parameters = [ 199 | 'locale' => 'bar' 200 | ]; 201 | 202 | $stream = Phony::mock(StreamInterface::class); 203 | $stream->__toString->returns($payload); 204 | 205 | $response = Phony::mock(ResponseInterface::class); 206 | $response->getBody->returns($stream->get()); 207 | 208 | $httpClient = Phony::mock(HttpClient::class); 209 | $httpClient->send->returns($response->get()); 210 | 211 | $results = $this->client->setHttpClient($httpClient->get()) 212 | ->getBusinessReviews($businessId, $parameters); 213 | 214 | $this->assertEquals(json_decode($payload), $results); 215 | 216 | Phony::inOrder( 217 | $httpClient->send->calledWith( 218 | $this->callback(function ($request) use ($path, $parameters) { 219 | $queryString = http_build_query($parameters); 220 | return $request->getMethod() === 'GET' 221 | && strpos((string) $request->getUri(), $path) !== false 222 | && ($queryString && strpos((string) $request->getUri(), $queryString) !== false); 223 | }) 224 | ), 225 | $response->getBody->called(), 226 | $stream->__toString->called() 227 | ); 228 | } 229 | 230 | public function testGetBusinessesSearchResults() 231 | { 232 | $path = '/v3/businesses/search'; 233 | $payload = $this->getResponseJson('business_search'); 234 | 235 | $parameters = [ 236 | 'term' => 'foo', 237 | 'location' => 'bar', 238 | 'latitude' => 1.0000, 239 | 'longitude' => 1.0000, 240 | 'radius' => 10, 241 | 'categories' => ['bars', 'french'], 242 | 'locale' => 'bar', 243 | 'limit' => 10, 244 | 'offset' => 2, 245 | 'sort_by' => 'best_match', 246 | 'price' => '1,2,3', 247 | 'open_now' => true, 248 | 'open_at' => 1234566, 249 | 'attributes' => ['hot_and_new','deals'] 250 | ]; 251 | 252 | $stream = Phony::mock(StreamInterface::class); 253 | $stream->__toString->returns($payload); 254 | 255 | $response = Phony::mock(ResponseInterface::class); 256 | $response->getBody->returns($stream->get()); 257 | 258 | $httpClient = Phony::mock(HttpClient::class); 259 | $httpClient->send->returns($response->get()); 260 | 261 | $results = $this->client->setHttpClient($httpClient->get()) 262 | ->getBusinessesSearchResults($parameters); 263 | 264 | $this->assertEquals(json_decode($payload), $results); 265 | 266 | Phony::inOrder( 267 | $httpClient->send->calledWith( 268 | $this->callback(function ($request) use ($path, $parameters) { 269 | $parameters['open_now'] = 'true'; 270 | $parameters['categories'] = implode(',', $parameters['categories']); 271 | $parameters['attributes'] = implode(',', $parameters['attributes']); 272 | $queryString = http_build_query($parameters); 273 | return $request->getMethod() === 'GET' 274 | && strpos((string) $request->getUri(), $path) !== false 275 | && ($queryString && strpos((string) $request->getUri(), $queryString) !== false); 276 | }) 277 | ), 278 | $response->getBody->called(), 279 | $stream->__toString->called() 280 | ); 281 | } 282 | 283 | public function testGetBusinessesSearchResultsByPhone() 284 | { 285 | $phone = 'foo-bar'; 286 | $path = '/v3/businesses/search/phone'; 287 | $payload = $this->getResponseJson('business_search_by_phone'); 288 | 289 | $stream = Phony::mock(StreamInterface::class); 290 | $stream->__toString->returns($payload); 291 | 292 | $response = Phony::mock(ResponseInterface::class); 293 | $response->getBody->returns($stream->get()); 294 | 295 | $httpClient = Phony::mock(HttpClient::class); 296 | $httpClient->send->returns($response->get()); 297 | 298 | $results = $this->client->setHttpClient($httpClient->get()) 299 | ->getBusinessesSearchResultsByPhone($phone); 300 | 301 | $this->assertEquals(json_decode($payload), $results); 302 | 303 | Phony::inOrder( 304 | $httpClient->send->calledWith( 305 | $this->callback(function ($request) use ($path, $phone) { 306 | $queryString = http_build_query(['phone' => $phone]); 307 | return $request->getMethod() === 'GET' 308 | && strpos((string) $request->getUri(), $path) !== false 309 | && strpos((string) $request->getUri(), $queryString) !== false; 310 | }) 311 | ), 312 | $response->getBody->called(), 313 | $stream->__toString->called() 314 | ); 315 | } 316 | 317 | public function testGetTransactionsSearchResultsByType() 318 | { 319 | $type = 'foo'; 320 | $path = '/v3/transactions/'.$type.'/search'; 321 | $payload = $this->getResponseJson('business_search_by_phone'); 322 | 323 | $parameters = [ 324 | 'latitude' => 1.0000, 325 | 'longitude' => 1.0000, 326 | 'location' => 'bar' 327 | ]; 328 | 329 | $stream = Phony::mock(StreamInterface::class); 330 | $stream->__toString->returns($payload); 331 | 332 | $response = Phony::mock(ResponseInterface::class); 333 | $response->getBody->returns($stream->get()); 334 | 335 | $httpClient = Phony::mock(HttpClient::class); 336 | $httpClient->send->returns($response->get()); 337 | 338 | $results = $this->client->setHttpClient($httpClient->get()) 339 | ->getTransactionsSearchResultsByType($type, $parameters); 340 | 341 | $this->assertEquals(json_decode($payload), $results); 342 | 343 | Phony::inOrder( 344 | $httpClient->send->calledWith( 345 | $this->callback(function ($request) use ($path, $parameters) { 346 | $queryString = http_build_query($parameters); 347 | return $request->getMethod() === 'GET' 348 | && strpos((string) $request->getUri(), $path) !== false 349 | && ($queryString && strpos((string) $request->getUri(), $queryString) !== false); 350 | }) 351 | ), 352 | $response->getBody->called(), 353 | $stream->__toString->called() 354 | ); 355 | } 356 | 357 | /** 358 | * @expectedException Stevenmaguire\Yelp\Exception\HttpException 359 | */ 360 | public function testClientRaisesExceptionWhenHttpRequestFails() 361 | { 362 | $businessId = 'foo'; 363 | $path = '/v3/businesses/'.$businessId; 364 | $payload = $this->getResponseJson('error'); 365 | 366 | // locale string Optional. Specify the locale to return the business information in. See the list of supported locales. 367 | 368 | $stream = Phony::mock(StreamInterface::class); 369 | $stream->__toString->returns($payload); 370 | 371 | $response = Phony::mock(ResponseInterface::class); 372 | $response->getBody->returns($stream->get()); 373 | 374 | $request = Phony::mock(RequestInterface::class); 375 | 376 | $httpClient = Phony::mock(HttpClient::class); 377 | $httpClient->send->throws(new BadResponseException( 378 | 'test exception', 379 | $request->get(), 380 | $response->get() 381 | )); 382 | 383 | $business = $this->client->setHttpClient($httpClient->get()) 384 | ->getBusiness($businessId); 385 | 386 | Phony::inOrder( 387 | $httpClient->send->calledWith( 388 | $this->callback(function ($request) use ($path) { 389 | return $request->getMethod() === 'GET' 390 | && strpos((string) $request->getUri(), $path) !== false; 391 | }) 392 | ), 393 | $response->getBody->called(), 394 | $stream->__toString->called() 395 | ); 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /tests/v3/autocomplete_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "terms": [ 3 | { 4 | "text": "Delivery" 5 | } 6 | ], 7 | "businesses": [ 8 | { 9 | "name": "Delfina", 10 | "id": "YqvoyaNvtoC8N5dA8pD2JA" 11 | }, 12 | { 13 | "text": "Delarosa", 14 | "id": "vu6PlPyKptsT6oEq50qOzA" 15 | }, 16 | { 17 | "text": "Pizzeria Delfina", 18 | "id": "bai6umLcCNy9cXql0Js2RQ" 19 | } 20 | ], 21 | "categories": [ 22 | { 23 | "alias": "delis", 24 | "title": "Delis" 25 | }, 26 | { 27 | "alias": "fooddeliveryservices", 28 | "title": "Food Delivery Services" 29 | }, 30 | { 31 | "alias": "couriers", 32 | "title": "Couriers & Delivery Services" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /tests/v3/business_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "gary-danko-san-francisco", 3 | "name": "Gary Danko", 4 | "image_url": "https://s3-media4.fl.yelpcdn.com/bphoto/--8oiPVp0AsjoWHqaY1rDQ/o.jpg", 5 | "is_claimed": false, 6 | "is_closed": false, 7 | "url": "https://www.yelp.com/biz/gary-danko-san-francisco", 8 | "price": "$$$$", 9 | "rating": 4.5, 10 | "review_count": 4521, 11 | "phone": "+14152520800", 12 | "photos": [ 13 | "http://s3-media3.fl.yelpcdn.com/bphoto/--8oiPVp0AsjoWHqaY1rDQ/o.jpg", 14 | "http://s3-media2.fl.yelpcdn.com/bphoto/ybXbObsm7QGw3SGPA1_WXA/o.jpg", 15 | "http://s3-media3.fl.yelpcdn.com/bphoto/7rZ061Wm4tRZ-iwAhkRSFA/o.jpg" 16 | ], 17 | "hours": [ 18 | { 19 | "hours_type": "REGULAR", 20 | "open": [ 21 | { 22 | "is_overnight": false, 23 | "end": "2200", 24 | "day": 0, 25 | "start": "1730" 26 | }, 27 | { 28 | "is_overnight": false, 29 | "end": "2200", 30 | "day": 1, 31 | "start": "1730" 32 | }, 33 | { 34 | "is_overnight": false, 35 | "end": "2200", 36 | "day": 2, 37 | "start": "1730" 38 | }, 39 | { 40 | "is_overnight": false, 41 | "end": "2200", 42 | "day": 3, 43 | "start": "1730" 44 | }, 45 | { 46 | "is_overnight": false, 47 | "end": "2200", 48 | "day": 4, 49 | "start": "1730" 50 | }, 51 | { 52 | "is_overnight": false, 53 | "end": "2200", 54 | "day": 5, 55 | "start": "1730" 56 | }, 57 | { 58 | "is_overnight": false, 59 | "end": "2200", 60 | "day": 6, 61 | "start": "1730" 62 | } 63 | ], 64 | "is_open_now": false 65 | } 66 | ], 67 | "categories": [ 68 | { 69 | "alias": "newamerican", 70 | "title": "American (New)" 71 | } 72 | ], 73 | "coordinates": { 74 | "latitude": 37.80587, 75 | "longitude": -122.42058 76 | }, 77 | 78 | "location": { 79 | "address1": "800 N Point St", 80 | "address2": "", 81 | "address3": "", 82 | "city": "San Francisco", 83 | "state": "CA", 84 | "zip_code": "94109", 85 | "country": "US", 86 | "display_address": [ 87 | "800 N Point St", 88 | "San Francisco, CA 94109" 89 | ], 90 | "cross_streets": "Hyde St & Larkin St" 91 | }, 92 | "transactions": ["restaurant_reservation"] 93 | } 94 | -------------------------------------------------------------------------------- /tests/v3/business_reviews_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "reviews": [ 3 | { 4 | "rating": 5, 5 | "user": { 6 | "image_url": "https://s3-media3.fl.yelpcdn.com/photo/iwoAD12zkONZxJ94ChAaMg/o.jpg", 7 | "name": "Ella A." 8 | }, 9 | "text": "Went back again to this place since the last time i visited the bay area 5 months ago, and nothing has changed. Still the sketchy Mission, Still the cashier...", 10 | "time_created": "2016-08-29 00:41:13", 11 | "url": "https://www.yelp.com/biz/la-palma-mexicatessen-san-francisco?hrid=hp8hAJ-AnlpqxCCu7kyCWA&adjust_creative=0sidDfoTIHle5vvHEBvF0w&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_reviews&utm_source=0sidDfoTIHle5vvHEBvF0w" 12 | }, 13 | { 14 | "rating": 4, 15 | "user": { 16 | "image_url": null, 17 | "name": "Yanni L." 18 | }, 19 | "text": "The \"restaurant\" is inside a small deli so there is no sit down area. Just grab and go.\n\nInside, they sell individually packaged ingredients so that you can...", 20 | "time_created": "2016-09-28 08:55:29", 21 | "url": "https://www.yelp.com/biz/la-palma-mexicatessen-san-francisco?hrid=fj87uymFDJbq0Cy5hXTHIA&adjust_creative=0sidDfoTIHle5vvHEBvF0w&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_reviews&utm_source=0sidDfoTIHle5vvHEBvF0w" 22 | }, 23 | { 24 | "rating": 4, 25 | "user": { 26 | "image_url": null, 27 | "name": "Suavecito M." 28 | }, 29 | "text": "Dear Mission District,\n\nI miss you and your many delicious late night food establishments and vibrant atmosphere. I miss the way you sound and smell on a...", 30 | "time_created": "2016-08-10 07:56:44", 31 | "url": "https://www.yelp.com/biz/la-palma-mexicatessen-san-francisco?hrid=m_tnQox9jqWeIrU87sN-IQ&adjust_creative=0sidDfoTIHle5vvHEBvF0w&utm_campaign=yelp_api_v3&utm_medium=api_v3_business_reviews&utm_source=0sidDfoTIHle5vvHEBvF0w" 32 | } 33 | ], 34 | "total": 3 35 | } 36 | -------------------------------------------------------------------------------- /tests/v3/business_search_by_phone_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "total": 1, 3 | "businesses": [ 4 | { 5 | "rating": 4.5, 6 | "price": "$$$$", 7 | "phone": "+14157492060", 8 | "id": "gary-danko-san-francisco", 9 | "categories": [ 10 | { 11 | "alias": "newamerican", 12 | "title": "American (New)" 13 | } 14 | ], 15 | "review_count": 4525, 16 | "name": "Gary Danko", 17 | "url": "https://www.yelp.com/biz/gary-danko-san-francisco", 18 | "coordinates": { 19 | "latitude": 37.80587, 20 | "longitude": -122.42058 21 | }, 22 | "image_url": "https://s3-media3.fl.yelpcdn.com/bphoto/--8oiPVp0AsjoWHqaY1rDQ/o.jpg", 23 | "is_closed": false, 24 | "location": { 25 | "city": "San Francisco", 26 | "country": "US", 27 | "address2": "", 28 | "address3": "", 29 | "state": "CA", 30 | "address1": "800 N Point St", 31 | "zip_code": "94109" 32 | }, 33 | "transactions": ["restaurant_reservation"] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /tests/v3/business_search_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "total": 8228, 3 | "businesses": [ 4 | { 5 | "rating": 4, 6 | "price": "$", 7 | "phone": "+14152520800", 8 | "id": "four-barrel-coffee-san-francisco", 9 | "is_closed": false, 10 | "categories": [ 11 | { 12 | "alias": "coffee", 13 | "title": "Coffee & Tea" 14 | } 15 | ], 16 | "review_count": 1738, 17 | "name": "Four Barrel Coffee", 18 | "url": "https://www.yelp.com/biz/four-barrel-coffee-san-francisco", 19 | "coordinates": { 20 | "latitude": 37.7670169511878, 21 | "longitude": -122.42184275 22 | }, 23 | "image_url": "http://s3-media2.fl.yelpcdn.com/bphoto/MmgtASP3l_t4tPCL1iAsCg/o.jpg", 24 | "location": { 25 | "city": "San Francisco", 26 | "country": "US", 27 | "address2": "", 28 | "address3": "", 29 | "state": "CA", 30 | "address1": "375 Valencia St", 31 | "zip_code": "94103" 32 | }, 33 | "distance": 1604.23, 34 | "transactions": ["pickup", "delivery"] 35 | }, 36 | // ... 37 | ], 38 | "region": { 39 | "center": { 40 | "latitude": 37.767413217936834, 41 | "longitude": -122.42820739746094 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/v3/error_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": { 3 | "text": "Invalid parameter", 4 | "id": "INVALID_PARAMETER", 5 | "field": "location" 6 | } 7 | } 8 | --------------------------------------------------------------------------------