View source
<?php
class views_geojson_bbox_argument extends views_handler_argument {
public function default_argument_form(&$form, &$form_state) {
parent::default_argument_form($form, $form_state);
$form['no_argument']['#title'] = 'When the filter value is NOT in the URL <em>as a normal Drupal argument</em>';
$form['empty_result'] = array(
'#type' => 'checkbox',
'#title' => t('Empty result on missing bounding box value'),
'#description' => t('When the argument is not found you may choose to show no result.'),
'#default_value' => $this->options['empty_result'],
);
}
public function option_definition() {
$options = parent::option_definition();
$options['arg_id'] = array(
'default' => 'bbox',
);
$options['empty_result'] = array(
'default' => FALSE,
'bool' => TRUE,
);
$options['bbox_wrap'] = array(
'default' => TRUE,
'bool' => TRUE,
);
return $options;
}
public function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['bbox_wrap'] = array(
'#type' => 'checkbox',
'#title' => t('Wrap the bounding box around 360 degrees.'),
'#description' => t('Depending on the projection of the data it is possible that the bounding box wraps around the edges of the map. This requires extra conditions in the views query. By default wrapping is enabled. Turn it of if the provided coordinates never wrap.'),
'#default_value' => $this->options['bbox_wrap'],
);
}
public function query($group_by = FALSE) {
if (empty($this->argument) || $this->view->base_field === 'search_api_id') {
return;
}
$this
->ensure_my_table();
$bbox = $this
->_explode_bbox_coords($this->argument);
if (empty($bbox)) {
$this->argument = FALSE;
$this->view->built = TRUE;
$this->view->executed = TRUE;
return;
}
if (isset($this->view->display_handler->display->display_options['style_options'])) {
$data_source = $this->view->display_handler->display->display_options['style_options']['data_source'];
}
else {
$data_source = $this->view->display['default']->display_options['style_options']['data_source'];
}
if ($data_source['value'] === 'latlon') {
$lat_field_obj = $this->view->field[$data_source['latitude']];
$lon_field_obj = $this->view->field[$data_source['longitude']];
$lat_field_table = $lat_field_obj->table;
$lon_field_table = $lon_field_obj->table;
}
elseif ($data_source['value'] === 'geofield') {
$lat_field_obj = $lon_field_obj = $this->view->field[$data_source['geofield']];
$lat_field_table = $lon_field_table = $lat_field_obj->table;
}
else {
$this->argument = FALSE;
$this->view->built = TRUE;
$this->view->executed = TRUE;
return;
}
if (isset($lat_field_obj->field_info) && $lat_field_obj->field_info['type'] === 'geofield') {
$lat_field_name = $lat_field_obj->field_info['storage']['details']['sql']['FIELD_LOAD_CURRENT'][$lat_field_table]['lat'];
}
else {
$lat_field_name = $lat_field_obj->real_field;
}
if (isset($lon_field_obj->field_info) && $lon_field_obj->field_info['type'] === 'geofield') {
$lon_field_name = $lon_field_obj->field_info['storage']['details']['sql']['FIELD_LOAD_CURRENT'][$lon_field_table]['lon'];
}
else {
$lon_field_name = $lon_field_obj->real_field;
}
$this->query
->ensure_table($lat_field_table);
if ($lon_field_table !== $lat_field_table) {
$this->query
->ensure_table($lon_field_table);
}
$left = $bbox['left'];
$bottom = $bbox['bottom'];
$right = $bbox['right'];
$top = $bbox['top'];
if ($this->options['bbox_wrap']) {
if ($right - $left < 360) {
$group = $this->query
->set_where_group('AND');
if ($left > -180 && $left <= 180) {
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", $left, '>=');
}
else {
$this->query
->set_where_group('OR', $group);
$left = ($left + 180) % 360;
if ($left <= 0) {
$left += 360;
}
$left -= 180;
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", array(
$left,
180,
), 'BETWEEN');
}
if ($right > -180 && $right <= 180) {
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", $right, '<=');
}
else {
$this->query
->set_where_group('OR', $group);
$right = ($right + 180) % 360;
if ($right <= 0) {
$right += 360;
}
$right -= 180;
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", array(
-180,
$right,
), 'BETWEEN');
}
}
}
else {
$group = $this->query
->set_where_group('AND');
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", $left, '>=');
$this->query
->add_where($group, "{$lon_field_table}.{$lon_field_name}", $right, '<=');
}
$group = $this->query
->set_where_group('AND');
$this->query
->add_where($group, "{$lat_field_table}.{$lat_field_name}", $bottom, '>=');
$this->query
->add_where($group, "{$lat_field_table}.{$lat_field_name}", $top, '<=');
}
private function _check_bbox_coords($bbox_coords) {
foreach ($bbox_coords as $coord) {
if (!is_numeric($coord)) {
return FALSE;
}
}
return TRUE;
}
private function _explode_bbox_coords($bbox_coords_str) {
if (!is_string($bbox_coords_str)) {
return array();
}
$bbox_coords = explode(',', $bbox_coords_str);
if (count($bbox_coords) === 4) {
if (!$this
->_check_bbox_coords($bbox_coords)) {
return array();
}
return array(
'left' => $bbox_coords[0],
'bottom' => $bbox_coords[1],
'right' => $bbox_coords[2],
'top' => $bbox_coords[3],
);
}
return array();
}
}