This commit is contained in:
bartek 2014-06-05 18:37:45 +00:00
commit 1247cc18e2

View file

@ -2,334 +2,343 @@
namespace joshtronic; namespace joshtronic;
/**
* GooglePlaces PHP wrapper
*/
class GooglePlaces class GooglePlaces
{ {
private $key = ''; private $key = '';
private $base_url = 'https://maps.googleapis.com/maps/api/place'; private $base_url = 'https://maps.googleapis.com/maps/api/place';
private $method = null; private $method = null;
private $response = null; private $response = null;
public $keyword = null; public $keyword = null;
public $language = 'en'; public $language = 'en';
public $location = null; public $location = null;
public $output = 'json'; public $output = 'json';
public $name = null; public $name = null;
public $pagetoken = null; public $pagetoken = null;
public $radius = null; public $radius = null;
public $rankby = 'prominence'; public $rankby = 'prominence';
public $sensor = false; public $sensor = false;
public $types = null; public $types = null;
public $reference = null; public $reference = null;
public $opennow = null; public $opennow = null;
public $subradius = null; public $subradius = null;
public $getmax = true; public $getmax = true;
private $grid = null; private $grid = null;
public function __construct($key) /**
{ * Constructor.
$this->key = $key; *
} * @param $key
*/
public function __construct($key)
{
$this->key = $key;
}
function __set($variable, $value) /**
{ * @param $variable
// Compensates for mixed variable naming * @param $value
$variable = str_replace('_', '', strtolower($variable)); */
$this->$variable = $value; function __set($variable, $value)
} {
// Compensates for mixed variable naming
$variable = str_replace('_', '', strtolower($variable));
$this->$variable = $value;
}
public function __call($method, $arguments) /**
{ * @param $method
$method = $this->method = strtolower($method); * @param $arguments
$url = implode('/', array($this->base_url, $method, $this->output)); * @return mixed|null
$parameters = array(); */
public function __call($method, $arguments)
{
$method = $this->method = strtolower($method);
$url = implode('/', array($this->base_url, $method, $this->output));
$parameters = array();
$parameters = $this->parameterBuilder($parameters); $parameters = $this->parameterBuilder($parameters);
$parameters = $this->methodChecker($parameters, $method); $parameters = $this->methodChecker($parameters, $method);
if (!empty($this->subradius)) { if (!empty($this->subradius)) {
return $this->subdivide($url, $parameters); return $this->subdivide($url, $parameters);
} }
return $this->queryGoogle($url, $parameters); return $this->queryGoogle($url, $parameters);
} }
/**
* Loops through all of our variables to make a parameter list
*/
private function parameterBuilder($parameters)
{
foreach (get_object_vars($this) as $variable => $value)
{
// Except these variables
if (!in_array($variable, array('base_url', 'method', 'output', 'pagetoken', 'response', 'subradius', 'getmax','grid')))
{
// Assuming it's not null
if ($value !== null)
{
// Converts boolean to string
if (is_bool($value))
{
$value = $value ? 'true' : 'false';
}
switch ($variable) /**
{ * Loops through all of our variables to make a parameter list
// Allows LatLng to be passed as an array *
case 'location': * @param $parameters
if (is_array($value)) * @return mixed
{ * @throws \Exception
// Just in case it's an associative array */
$value = array_values($value); private function parameterBuilder($parameters)
$value = $value[0] . ',' . $value[1]; {
} foreach (get_object_vars($this) as $variable => $value) {
break; // Except these variables
if (!in_array($variable, array('base_url', 'method', 'output',
'pagetoken', 'response', 'subradius', 'getmax', 'grid'))) {
// Assuming it's not null
if ($value !== null) {
// Converts boolean to string
if (is_bool($value)) {
$value = $value ? 'true' : 'false';
}
// Checks that the output is value switch ($variable) {
case 'output': // Allows LatLng to be passed as an array
$value = strtolower($value); case 'location':
if (is_array($value)) {
// Just in case it's an associative array
$value = array_values($value);
$value = $value[0] . ',' . $value[1];
}
break;
if (!in_array($value, array('json', 'xml'))) // Checks that the output is value
{ case 'output':
throw new \Exception('Invalid output, please specify either "json" or "xml".'); $value = strtolower($value);
}
break;
// Checks that it's a value rank by value if (!in_array($value, array('json', 'xml'))) {
case 'rankby': throw new \Exception('Invalid output, please specify either "json" or "xml".');
$value = strtolower($value); }
break;
if (!in_array($value, array('prominence', 'distance'))) // Checks that it's a value rank by value
{ case 'rankby':
throw new \Exception('Invalid rank by value, please specify either "prominence" or "distance".'); $value = strtolower($value);
}
break;
// Allows types to be passed as an array if (!in_array($value, array('prominence', 'distance'))) {
case 'types': throw new \Exception(
if (is_array($value)) 'Invalid rank by value, please specify either "prominence" or "distance".'
{ );
$value = implode('|', $value); }
} break;
break;
}
$parameters[$variable] = $value; // Allows types to be passed as an array
} case 'types':
} if (is_array($value)) {
} $value = implode('|', $value);
return $parameters; }
} break;
}
/** $parameters[$variable] = $value;
* takes the parameters and method to throw exceptions or modify parameters as needed }
* @todo Method to sanity check passed types }
*/ }
private function methodChecker($parameters, $method) return $parameters;
{ }
if (!isset($parameters['pagetoken']))
{
switch ($method)
{
case 'nearbysearch':
if (!isset($parameters['location']))
{
throw new \Exception('You must specify a location before calling nearbysearch().');
}
elseif (isset($parameters['rankby']))
{
switch ($parameters['rankby'])
{
case 'distance':
if (!isset($parameters['keyword']) && !isset($parameters['name']) && !isset($parameters['types']))
{
throw new \Exception('You much specify at least one of the following: keyword, name, types.');
}
if (isset($parameters['radius']))
{
unset($parameters['radius']);
}
break;
case 'prominence': /**
if (!isset($parameters['radius'])) * Takes the parameters and method to throw exceptions or modify parameters as needed
{ * @todo Method to sanity check passed types
throw new \Exception('You must specify a radius.'); *
} * @param $parameters
break; * @param $method
} * @return mixed
} * @throws \Exception
*/
private function methodChecker($parameters, $method)
{
if (!isset($parameters['pagetoken'])) {
switch ($method) {
case 'nearbysearch':
if (!isset($parameters['location'])) {
throw new \Exception('You must specify a location before calling nearbysearch().');
} elseif (isset($parameters['rankby'])) {
switch ($parameters['rankby']) {
case 'distance':
if (!isset($parameters['keyword']) && !isset($parameters['name']) && !isset($parameters['types'])) {
throw new \Exception('You much specify at least one of the following: keyword, name, types.');
}
break; if (isset($parameters['radius'])) {
unset($parameters['radius']);
}
break;
case 'radarsearch': case 'prominence':
if (!isset($parameters['location'])) if (!isset($parameters['radius'])) {
{ throw new \Exception('You must specify a radius.');
throw new \Exception('You must specify a location before calling nearbysearch().'); }
} break;
elseif (!isset($parameters['radius'])) }
{ }
throw new \Exception('You must specify a radius.');
}
elseif (empty($parameters['keyword']) && empty($parameters['name']) && empty($parameters['types']))
{
throw new \Exception('A Radar Search request must include at least one of keyword, name, or types.');
}
if (isset($parameters['rankby'])) break;
{
unset($parameters['rankby']);
}
break; case 'radarsearch':
if (!isset($parameters['location'])) {
throw new \Exception('You must specify a location before calling nearbysearch().');
} elseif (!isset($parameters['radius'])) {
throw new \Exception('You must specify a radius.');
} elseif (empty($parameters['keyword']) && empty($parameters['name']) && empty($parameters['types'])) {
throw new \Exception('A Radar Search request must include at least one of keyword, name, or types.'
);
}
case 'details': if (isset($parameters['rankby'])) {
if (!isset($parameters['reference'])) unset($parameters['rankby']);
{ }
throw new \Exception('You must specify a reference before calling details().');
}
if (isset($parameters['rankby'])) break;
{
unset($parameters['rankby']);
}
break; case 'details':
} if (!isset($parameters['reference'])) {
} throw new \Exception('You must specify a reference before calling details().');
return $parameters; }
}
/** if (isset($parameters['rankby'])) {
* Submits request via curl, sets the response, then returns the response unset($parameters['rankby']);
*/ }
private function queryGoogle($url, $parameters)
{
if ($this->pagetoken !== null)
{
$parameters['pagetoken'] = $this->pagetoken;
sleep(3);
}
// Couldn't seem to get http_build_query() to work right so... break;
$querystring = ''; }
}
return $parameters;
}
foreach ($parameters as $variable => $value) /**
{ * Submits request via curl, sets the response, then returns the response
if ($querystring != '') *
{ * @param $url
$querystring .= '&'; * @param $parameters
} * @return mixed
* @throws \Exception
*/
private function queryGoogle($url, $parameters)
{
if ($this->pagetoken !== null) {
$parameters['pagetoken'] = $this->pagetoken;
sleep(3);
}
$querystring .= $variable . '=' . $value; // Couldn't seem to get http_build_query() to work right so...
} $querystring = '';
$curl = curl_init(); foreach ($parameters as $variable => $value) {
if ($querystring != '') {
$querystring .= '&';
}
$options = array( $querystring .= $variable . '=' . $value;
CURLOPT_URL => $url . '?' . $querystring, }
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_RETURNTRANSFER => true,
);
curl_setopt_array($curl, $options); $curl = curl_init();
$response = curl_exec($curl); $options = array(
CURLOPT_URL => $url . '?' . $querystring,
CURLOPT_HEADER => false,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_RETURNTRANSFER => true,
);
if ($error = curl_error($curl)) curl_setopt_array($curl, $options);
{
throw new \Exception('CURL Error: ' . $error);
}
if ($this->output == 'json') $response = curl_exec($curl);
{
$response = json_decode($response, true);
if ($response === null) if ($error = curl_error($curl)) {
{ throw new \Exception('CURL Error: ' . $error);
throw new \Exception('The returned JSON was malformed or nonexistent.'); }
}
}
else
{
throw new \Exception('XML is terrible, don\'t use it, ever.');
}
curl_close($curl); if ($this->output == 'json') {
$response = json_decode($response, true);
$this->response = $response; if ($response === null) {
throw new \Exception('The returned JSON was malformed or nonexistent.');
}
} else {
throw new \Exception('XML is terrible, don\'t use it, ever.');
}
return $this->response; curl_close($curl);
}
/** $this->response = $response;
* Returns the longitude equal to a given distance (meters) at a given latitude
*/
public function meters2lng($meters, $latitude)
{
return $meters / (cos(deg2rad($latitude)) * 40075160 / 360);
}
/** return $this->response;
* Returns the latitude equal to a given distance (meters) }
*/
public function meters2lat($meters)
{
return $meters / (40075160 / 360);
}
/** /**
* Returns the aggregated responses for a subdivided search * Returns the longitude equal to a given distance (meters) at a given latitude
*/ *
private function subdivide($url, $parameters) * @param $meters
{ * @param $latitude
if (($this->radius % $this->subradius) || ($this->subradius < 200) || (($this->radius / $this->subradius) % 2)) * @return float
{ */
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)'); public function meters2lng($meters, $latitude)
} {
return $meters / (cos(deg2rad($latitude)) * 40075160 / 360);
}
$center = explode(',', $this->location); /**
$centerlat = $center[0]; * Returns the latitude equal to a given distance (meters)
$centerlng = $center[1]; *
$count = $this->radius / $this->subradius; * @param $meters
$lati = $this->meters2lat($this->subradius * 2); * @return float
*/
public function meters2lat($meters)
{
return $meters / (40075160 / 360);
}
$this->grid['results'] = array(); /**
* Returns the aggregated responses for a subdivided search
*
* @param $url
* @param $parameters
* @return null
* @throws \Exception
*/
private function subdivide($url, $parameters)
{
if (($this->radius % $this->subradius) || ($this->subradius < 200) || (($this->radius / $this->subradius) % 2)) {
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)');
}
for ($i = $count / 2 * -1; $i <= $count / 2; $i++) $center = explode(',', $this->location);
{ $centerlat = $center[0];
$lat = $centerlat + $i * $lati; $centerlng = $center[1];
$lngi = $this->meters2lng($this->subradius * 2, $lat); $count = $this->radius / $this->subradius;
$lati = $this->meters2lat($this->subradius * 2);
for ($j = $count / 2 * -1; $j <= $count / 2; $j++) $this->grid['results'] = array();
{
$lng = $centerlng + $j * $lngi;
$loc = $lat . ',' . $lng;
$parameters['location'] = $loc; for ($i = $count / 2 * -1; $i <= $count / 2; $i++) {
$parameters['radius'] = $this->subradius; $lat = $centerlat + $i * $lati;
$lngi = $this->meters2lng($this->subradius * 2, $lat);
$this->queryGoogle($url, $parameters); for ($j = $count / 2 * -1; $j <= $count / 2; $j++) {
$lng = $centerlng + $j * $lngi;
$loc = $lat . ',' . $lng;
$this->grid[$i][$j] = $this->response; $parameters['location'] = $loc;
$this->grid['results'] = array_merge($this->grid['results'], $this->response['results']); $parameters['radius'] = $this->subradius;
while ($this->response['next_page_token']) $this->queryGoogle($url, $parameters);
{
$this->pagetoken = $this->response['next_page_token'];
$this->queryGoogle($url, $parameters); $this->grid[$i][$j] = $this->response;
$this->grid['results'] = array_merge($this->grid['results'], $this->response['results']);
$this->grid[$i][$j] = array_merge($this->grid[$i][$j], $this->response); while ($this->response['next_page_token']) {
$this->grid['results'] = array_merge($this->grid['results'], $this->response['results']); $this->pagetoken = $this->response['next_page_token'];
$this->pagetoken = null;
}
}
}
return $this->grid; $this->queryGoogle($url, $parameters);
}
$this->grid[$i][$j] = array_merge($this->grid[$i][$j], $this->response);
$this->grid['results'] = array_merge($this->grid['results'], $this->response['results']);
$this->pagetoken = null;
}
}
}
return $this->grid;
}
} }
?>