diff --git a/src/GooglePlaces.php b/src/GooglePlaces.php index feb648e..8cbcfd8 100644 --- a/src/GooglePlaces.php +++ b/src/GooglePlaces.php @@ -5,6 +5,7 @@ namespace joshtronic; class GooglePlaces { public $client = ''; + public $sleep = 3; private $key = ''; private $base_url = 'https://maps.googleapis.com/maps/api/place'; private $method = null; @@ -30,7 +31,7 @@ class GooglePlaces private $exceptions = array( 'base_url', 'client', 'exceptions', 'getmax', 'grid', 'method', - 'output', 'pagetoken', 'response', 'subradius', + 'output', 'pagetoken', 'response', 'sleep', 'subradius', ); public function __construct($key, $client = false) @@ -48,6 +49,13 @@ class GooglePlaces public function __call($method, $arguments) { + $this->output = strtolower($this->output); + + if (!in_array($this->output, array('json', 'xml'))) + { + throw new \Exception('Invalid output, please specify either "json" or "xml".'); + } + $method = $this->method = strtolower($method); $url = implode('/', array($this->base_url, $method, $this->output)); $parameters = array(); @@ -98,16 +106,6 @@ class GooglePlaces } break; - // Checks that the output is value - case 'output': - $value = strtolower($value); - - if (!in_array($value, array('json', 'xml'))) - { - throw new \Exception('Invalid output, please specify either "json" or "xml".'); - } - break; - // Checks that it's a value rank by value case 'rankby': $value = strtolower($value); @@ -158,12 +156,12 @@ class GooglePlaces && !isset($parameters['name']) && !isset($parameters['types'])) { - throw new \Exception('You much specify at least one of the following: keyword, name, types.'); + throw new \Exception('You much specify at least one of the following: "keyword", "name", "types".'); } if (isset($parameters['radius'])) { - unset($parameters['radius']); + unset($this->radius, $parameters['radius']); } break; @@ -191,12 +189,12 @@ class GooglePlaces && empty($parameters['name']) && empty($parameters['types'])) { - throw new \Exception('A Radar Search request must include at least one of keyword, name, or types.'); + throw new \Exception('You much specify at least one of the following: "keyword", "name", "types".'); } if (isset($parameters['rankby'])) { - unset($parameters['rankby']); + unset($this->rankby, $parameters['rankby']); } break; @@ -205,12 +203,12 @@ class GooglePlaces if (!(isset($parameters['reference']) ^ isset($parameters['placeid']))) { - throw new \Exception('You must specify either a placeid or a reference (but not both) before calling details().'); + throw new \Exception('You must specify either a "placeid" or a "reference" (but not both) before calling details().'); } if (isset($parameters['rankby'])) { - unset($parameters['rankby']); + unset($this->rankby, $parameters['rankby']); } break; @@ -229,7 +227,7 @@ class GooglePlaces if ($this->pagetoken !== null) { $parameters['pagetoken'] = $this->pagetoken; - sleep(3); + sleep($this->sleep); } // Couldn't seem to get http_build_query() to work right so... @@ -287,17 +285,22 @@ class GooglePlaces */ private function subdivide($url, $parameters) { - if ($this->radius % $this->subradius - || $this->subradius < 200 - || ($this->radius / $this->subradius) % 2) + if ($this->subradius < 200) { - throw new \Exception('Subradius should divide evenly into radius. Also, subradius should be 200 meters or so. (ex: 2000/200 = 10x10 grid. NOT 2000/33 = 60.6x60.6 grid. NOT 2000/16 = 125x125 grid)'); + throw new \Exception('Subradius should be at least 200 meters.'); } - $center = explode(',', $this->location); + $quotient = $parameters['radius'] / $this->subradius; + + if ($parameters['radius'] % $this->subradius || $quotient % 2) + { + throw new \Exception('Subradius should divide evenly into radius.'); + } + + $center = explode(',', $parameters['location']); $centerlat = $center[0]; $centerlng = $center[1]; - $count = $this->radius / $this->subradius; + $count = $quotient; $lati = $this->meters2lat($this->subradius * 2); $this->grid['results'] = array(); @@ -315,31 +318,28 @@ class GooglePlaces $parameters['location'] = $loc; $parameters['radius'] = $this->subradius; - $this->queryGoogle($url, $parameters); + $pagetoken = true; - $this->grid[$i][$j] = $this->response; - - $this->grid['results'] = array_merge( - $this->grid['results'], - $this->response['results'] - ); - - while ($this->response['next_page_token']) + while ($pagetoken) { - $this->pagetoken = $this->response['next_page_token']; - $this->response = $this->client->get($url, $parameters); + $this->queryGoogle($url, $parameters); - $this->grid[$i][$j] = array_merge( - $this->grid[$i][$j], - $this->response - ); + $this->grid[$i][$j] = $this->response; $this->grid['results'] = array_merge( $this->grid['results'], $this->response['results'] ); - $this->pagetoken = null; + if (isset($this->response['next_page_token'])) + { + $this->pagetoken = $this->response['next_page_token']; + } + else + { + $this->pagetoken = null; + $pagetoken = false; + } } } } diff --git a/src/GooglePlacesClient.php b/src/GooglePlacesClient.php index 499a603..9a7ca30 100644 --- a/src/GooglePlacesClient.php +++ b/src/GooglePlacesClient.php @@ -2,7 +2,7 @@ namespace joshtronic; -class GooglePlacesClient implements GooglePlacesInterface +class GooglePlacesClient { public function get($url) { diff --git a/src/GooglePlacesInterface.php b/src/GooglePlacesInterface.php deleted file mode 100644 index 582513e..0000000 --- a/src/GooglePlacesInterface.php +++ /dev/null @@ -1,9 +0,0 @@ -places = new joshtronic\GooglePlaces(''); + $this->places = new joshtronic\GooglePlaces(''); + $this->places->sleep = 0; + } + + private function clientSetUp($next = false) + { + $client = $this->getMock('GooglePlacesClient', array('get')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + ' . ($next ? '"next_page_token" : "...",' : '') . ' + "results" : [], + "status" : "OK" + } + ')); + + $this->places->client = $client; } public function testSetVariable() @@ -21,32 +40,13 @@ class GooglePlacesTest extends PHPUnit_Framework_TestCase public function testNearbySearchProximity() { - $client = $this->getMock('GooglePlacesInterface', array('get')); - - $client->expects($this->exactly(1)) - ->method('get') - ->will($this->returnValue(' - { - "html_attributions" : [], - "next_page_token" : "...", - "results" : [ - { }, - { }, - { }, - { }, - { } - ], - "status" : "OK" - } - ')); - - $this->places->client = $client; + $this->clientSetUp(true); $this->places->location = array(-33.86820, 151.1945860); $this->places->radius = 800; $results = $this->places->nearbySearch(); $this->assertTrue(is_array($results['results'])); - $this->assertEquals("OK", $results['status']); + $this->assertEquals('OK', $results['status']); } /** @@ -55,7 +55,230 @@ class GooglePlacesTest extends PHPUnit_Framework_TestCase */ public function testNearbySearchWithoutLocation() { - $results = $this->places->nearbySearch(); + $this->places->nearbySearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You must specify a radius. + */ + public function testNearbySearchWithoutRadius() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->nearbySearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage Invalid output, please specify either "json" or "xml". + */ + public function testNearbySearchInvalidOutput() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 800; + $this->places->output = 'foo'; + $this->places->nearbySearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage Invalid rank by value, please specify either "prominence" or "distance". + */ + public function testNearbySearchInvalidRankBy() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 800; + $this->places->rankby = 'foo'; + $this->places->nearbySearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You much specify at least one of the following: "keyword", "name", "types". + */ + public function testNearbySearchMissingParameters() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->rankby = 'distance'; + $this->places->nearbySearch(); + } + + public function testNearbySearchUnsetRadius() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->rankby = 'distance'; + $this->places->keyword = 'cafe'; + $this->places->radius = 800; + $results = $this->places->nearbySearch(); + + $this->assertFalse(isset($this->places->radius)); + } + + public function testNearbySearchDistance() + { + $client = $this->getMock('GooglePlacesClient', array('get')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + "next_page_token" : "...", + "results" : [], + "status" : "OK" + } + ')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + "results" : [], + "status" : "OK" + } + ')); + + $this->places->client = $client; + $this->places->location = array(-33.86820, 151.1945860); + $this->places->rankby = 'distance'; + $this->places->types = array('restaurant', 'business'); + $results = $this->places->nearbySearch(); + + $this->assertTrue(is_array($results['results'])); + $this->assertEquals('OK', $results['status']); + } + + public function testSetPageToken() + { + $client = $this->getMock('GooglePlacesClient', array('get')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + "next_page_token" : "...", + "results" : [], + "status" : "OK" + } + ')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + "results" : [], + "status" : "OK" + } + ')); + + $this->places->client = $client; + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 100; + $this->places->pagetoken = '...'; + $results = $this->places->nearbySearch(); + + $this->assertTrue(is_array($results['results'])); + $this->assertEquals('OK', $results['status']); + } + + public function testRadarSearch() + { + $this->clientSetUp(); + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 100; + $this->places->keyword = 'restaurant'; + $results = $this->places->radarSearch(); + + $this->assertTrue(is_array($results['results'])); + $this->assertEquals('OK', $results['status']); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You must specify a location before calling radarsearch(). + */ + public function testRadarSearchWithoutLocation() + { + $this->places->radarSearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You must specify a radius. + */ + public function testRadarSearchWithoutRadius() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radarSearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You much specify at least one of the following: "keyword", "name", "types". + */ + public function testRadarSearchMissingParameters() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 100; + $this->places->radarSearch(); + } + + public function testDetails() + { + $this->clientSetUp(); + $this->places->placeid = '123'; + $this->places->rankby = 'distance'; + $results = $this->places->details(); + + $this->assertTrue(is_array($results['results'])); + $this->assertEquals('OK', $results['status']); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage You must specify either a "placeid" or a "reference" (but not both) before calling details(). + */ + public function testDetailsMissingParameters() + { + $this->places->details(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage The returned JSON was malformed or nonexistent. + */ + public function testInvalidJSON() + { + $client = $this->getMock('GooglePlacesClient', array('get')); + + $client + ->expects($this->once()) + ->method('get') + ->will($this->returnValue('[{ foo: "ba"r,, }];')); + + $this->places->client = $client; + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 100; + $this->places->nearbysearch(); + } + + /** + * @expectedException Exception + * @expectedExceptionMessage XML is terrible, don't use it, ever. + */ + public function testOutputXML() + { + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 800; + $this->places->output = 'xml'; + $this->places->nearbySearch(); } public function testMeters2Lng() @@ -74,24 +297,67 @@ class GooglePlacesTest extends PHPUnit_Framework_TestCase ); } - public function testNearbySearchDistance() + public function testNearbySearchProximitySubradius() { + $client = $this->getMock('GooglePlacesClient', array('get')); + for ($i = 0; $i < 18; $i++) + { + $client + ->expects($this->at($i)) + ->method('get') + ->will($this->returnValue(' + { + "html_attributions" : [], + ' . ($i % 2 ? '' : '"next_page_token" : "...",') . ' + "results" : [{}, {}], + "status" : "OK" + } + ')); + } + + $this->places->client = $client; + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 400; + $this->places->subradius = 200; + $results = $this->places->nearbySearch(); + + $this->assertTrue(is_array($results['results'])); + $this->assertEquals(36, count($results['results'])); } - public function testNearbySearchPagination() + /** + * @expectedException Exception + * @expectedExceptionMessage Subradius should be at least 200 meters + */ + public function testNearbySearchProximitySubradiusBelow200() { - + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 2000; + $this->places->subradius = 100; + $results = $this->places->nearbySearch(); } - public function testRadarSearch() + /** + * @expectedException Exception + * @expectedExceptionMessage Subradius should divide evenly into radius. + */ + public function testNearbySearchProximitySubradiusDivisionError() { - + $this->places->location = array(-33.86820, 151.1945860); + $this->places->radius = 2000; + $this->places->subradius = 233; + $results = $this->places->nearbySearch(); } - public function testDetails() + /** + * @expectedException Exception + * @expectedExceptionMessage CURL Error: Could not resolve host: bar + */ + public function testClientError() { - + $client = new joshtronic\GooglePlacesClient(); + $client->get('http://foo@bar:google.com'); } }