Skip to content

Instantly share code, notes, and snippets.

@zetas
Created June 6, 2014 09:37
Show Gist options
  • Save zetas/0b96cbaec9676de834ac to your computer and use it in GitHub Desktop.
Save zetas/0b96cbaec9676de834ac to your computer and use it in GitHub Desktop.
Spartz Controller
<?php
/**
* Created by DavidDV <[email protected]>
* For project Spartz
* Created: 6/3/14
* <http://[github|bitbucket].com/zetas>
*/
class APIController extends BaseController {
private $R = 6371; // Earth's mean radius in km
private function _pull($query, $single = false, $limit = 1000, $from = 0) {
if ($single)
return $query->firstOrFail();
if ($query->count() == 0) {
App::abort(404);
}
return $query->skip($from)->take($limit)->get();
}
private function _calculate_minmax($lat, $lon, $rad) {
$maxLat = $lat + rad2deg($rad/$this->R);
$minLat = $lat - rad2deg($rad/$this->R);
// compensate for degrees longitude getting smaller with increasing latitude
$maxLon = $lon + rad2deg($rad/$this->R/cos(deg2rad($lat)));
$minLon = $lon - rad2deg($rad/$this->R/cos(deg2rad($lat)));
return array('maxLat' => $maxLat, 'minLat' => $minLat, 'maxLon' => $maxLon, 'minLon' => $minLon);
}
public function showCities($state) {
// @TODO: Not dry, it's wet-as-hell actually, repeated in almost every action. Top priority refactor.
$limit = abs(Input::get('limit', 1000));
$from = abs(Input::get('from', 0));
$query = City::whereState($state);
return Response::json($this->_pull($query, false, $limit, $from));
}
public function showCityRadius($state, $city) {
$limit = abs(Input::get('limit', 1000));
$from = abs(Input::get('from', 0));
$radiusMI = abs(Input::get('radius', 100));
($radiusMI > 500) ? $radiusMI = 500 : null; #Cap radius at 500
$ratio = 1.609344; //For converting MI to KM
$rad = $radiusMI*$ratio;
$query = City::whereState($state)->whereName($city);
$c = $this->_pull($query, true);
$minMax = $this->_calculate_minmax($c->latitude, $c->longitude, $rad);
$lat = deg2rad($c->latitude);
$lon = deg2rad($c->longitude);
/*
* Special thanks for this mathematical wonder go to
* http://www.movable-type.co.uk/scripts/latlong-db.html
*/
$cities = City::select(DB::raw('id, name, state, latitude, longitude, acos(sin(?)*sin(radians(latitude)) + cos(?)*cos(radians(latitude))*cos(radians(longitude)-?)) * ? As D'))
->from(DB::raw('(Select id, name, state, latitude, longitude From cities Where latitude Between ? And ? And longitude Between ? And ?) As FirstCut'))
->whereRaw('acos(sin(?)*sin(radians(latitude)) + cos(?)*cos(radians(latitude))*cos(radians(longitude)-?)) * ? < ? AND id != ?')
->orderBy('D')
->skip($from)->take($limit)
->setBindings([$lat, $lat, $lon, $this->R, $minMax['minLat'], $minMax['maxLat'], $minMax['minLon'], $minMax['maxLon'], $lat, $lat, $lon, $this->R, $rad, $c->id])
->get();
return Response::json($cities);
}
public function showVisits($user) {
$limit = abs(Input::get('limit', 1000));
$from = abs(Input::get('from', 0));
$u = User::findOrFail($user);
$visits = $u->visits()->skip($from)->take($limit)->get();
return View::make('visits', array('visits' => $visits));
}
/**
* Notes:
* I figure we allow them to save multiple visits to the same place,
* maybe it's a travel log.
*/
public function addVisit($user) {
// @TODO: Not Dry. Also, insecure. (you could hammer user id's to find which is legit)
$u = User::findOrFail($user);
$json = Input::get('json');
$data = json_decode($json, true);
if (!array_key_exists('city', $data) || !array_key_exists('state', $data))
App::abort(404, 'Improperly formatted JSON.');
/*
* @TODO: Not Dry, put this common query into a model scope, and the _pull as a validator.
* In addition, we're using inputs directly in a query builder statement. Hopefully the QB escapes it.
* If this were a real project, i'd need to research this and possibly fix it with proper validators.
*/
$query = City::whereState($data['state'])->whereName($data['city']);
$c = $this->_pull($query, true);
// @TODO: Fix this to use the ORM to manage the relationship.
$visit = new Visit();
$visit->city_id = $c->id;
$visit->user_id = $u->id;
$visit->save();
/*
* Since we would have generated an error by now if something was wrong...
*
* Might want to change this to a simple redirect back to the list but as
* I assume this would be for an api, redirecting on completion is not ideal.
*/
return 'Added!';
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment