Skip to content

Instantly share code, notes, and snippets.

@Oshuma
Created April 15, 2009 16:28
Show Gist options
  • Select an option

  • Save Oshuma/95887 to your computer and use it in GitHub Desktop.

Select an option

Save Oshuma/95887 to your computer and use it in GitHub Desktop.
<?php
class SearchController extends AppController
{
var $name = 'Search';
var $uses = array('Address', 'LiftVendor', 'SubVendor', 'ZipCode');
/* Search by zip code. */
function zip($zip_code) {
set_time_limit(0); // Because this action could take a while...
$this->layout = false; // Used through Ajax, so don't need a layout.
if (!$zip_code) $this->error_redirect('Must pass a Zip Code', $this->home_path($current_user['User']));
// The model that we're searching for.
if (isset($this->passedArgs['model']))
$model = $this->passedArgs['model'];
else
$this->error_redirect('Must pass a model name.', $this->home_path($current_user['User']));
// Range in miles.
if (isset($this->passedArgs['range'])) {
$range = $this->passedArgs['range'];
} else {
$range = 5;
}
$zip_ranges = $this->ZipCode->find_in_range($zip_code, $range);
foreach ($zip_ranges as $zip) {
$record = $this->$model->find('first', array(
'conditions' => array('Address.zip' => $zip['ZipCode']['zip'])));
if ($record) {
$record['distance'] = $zip['distance'];
$records[] = $record;
}
}
if (isset($records)) {
usort($records, array('SearchController', '_sort_by_distance'));
$this->set('records', $records);
}
$this->set('model', $model);
}
private function _sort_by_distance($zip1, $zip2) {
$first = $zip1['distance'];
$second = $zip2['distance'];
if ($first == $second) return 0;
return ($first < $second) ? -1 : 1;
}
}
?>
<?php
class ZipCode extends AppModel
{
var $name = 'ZipCode';
var $validate = array(
'zip' => array('numeric'),
'latitude' => array('decimal'),
'longitude' => array('decimal'),
'city' => array('notEmpty'),
'state' => array('notEmpty'),
'county' => array('notEmpty')
);
function find_in_range($zip_code, $range = 5) {
$zip = $this->find('first', array(
'recursive' => -1,
'conditions' => array('zip' => $zip_code)));
// Calculate the latitude/longitude ranges.
$latitude_range = $range / 69.172;
$longitude_range = abs($range / (cos($zip['ZipCode']['longitude']) * 69.172));
$min_latitude = $zip['ZipCode']['latitude'] - $latitude_range;
$max_latitude = $zip['ZipCode']['latitude'] + $latitude_range;
$min_longitude = $zip['ZipCode']['longitude'] - $longitude_range;
$max_longitude = $zip['ZipCode']['longitude'] + $longitude_range;
$zip_ranges = $this->_in_range($min_latitude,
$max_latitude,
$min_longitude,
$max_longitude);
// Need to pass by reference, so we can modify the result.
foreach ($zip_ranges as &$location) {
$start = array($zip['ZipCode']['latitude'], $location['ZipCode']['latitude']);
$end = array($zip['ZipCode']['longitude'], $location['ZipCode']['longitude']);
$location['distance'] = $this->_calculate_distance($start, $end);
}
return $zip_ranges;
}
function _calculate_distance($start = array(), $end = array()) {
$earth_radius = 3959;
$div = 57.2958;
$calc = (sin($start[0]/$div) * (sin($start[1]/$div)) + (cos($start[0]/$div) * (cos($start[1]/$div) * cos(($end[0]/$div) - ($end[1]/$div)))));
$miles = $earth_radius * atan2(sqrt(1 - (pow($calc, 2))), $calc);
return $miles;
}
private function _in_range($min_lat, $max_lat, $min_long, $max_long) {
$this->log("Finding zip codes within: ($min_lat, $max_lat) - ($min_long, $max_long)", LOG_DEBUG);
$zip_ranges = $this->find('all', array(
'recursive' => -1,
'conditions' => array(
'ZipCode.latitude BETWEEN ? AND ?' => array($min_lat, $max_lat),
'ZipCode.longitude BETWEEN ? AND ?' => array($min_long, $max_long)
) // conditions
)); // find()
return $zip_ranges;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment