View source
<?php
namespace Drupal\geofield\Plugin\views\argument;
use Drupal\geofield\WktGenerator;
use Drupal\views\Plugin\views\argument\Formula;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\geofield\Plugin\GeofieldProximitySourceManager;
use Drupal\Core\Render\Markup;
class GeofieldProximityArgument extends Formula implements ContainerFactoryPluginInterface {
protected $wktGenerator;
protected $proximitySourceManager;
protected $sourcePlugin;
protected $units;
protected function decodeUnits() {
return [
'km' => [
'label' => $this
->t('Kilometers'),
'value' => 'GEOFIELD_KILOMETERS',
],
'm' => [
'label' => $this
->t('Meters'),
'value' => 'GEOFIELD_METERS',
],
'mi' => [
'label' => $this
->t('Miles'),
'value' => 'GEOFIELD_MILES',
],
'yd' => [
'label' => $this
->t('Yards'),
'value' => 'GEOFIELD_YARDS',
],
'ft' => [
'label' => $this
->t('Feet'),
'value' => 'GEOFIELD_FEET',
],
'nmi' => [
'label' => $this
->T('Nautical MIles'),
'value' => 'GEOFIELD_NAUTICAL_MILES',
],
];
}
protected function unitsListMarkup() {
$markup = '';
foreach ($this->units as $k => $unit) {
$markup .= '<br><strong>' . $k . '</strong> (for ' . $unit['label'] . ')';
}
return $markup;
}
public function __construct(array $configuration, $plugin_id, $plugin_definition, WktGenerator $wkt_generator, GeofieldProximitySourceManager $proximity_source_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->wktGenerator = $wkt_generator;
$this->proximitySourceManager = $proximity_source_manager;
$this->units = $this
->decodeUnits();
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('geofield.wkt_generator'), $container
->get('plugin.manager.geofield_proximity_source'));
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$form['description']['#markup'] .= $this
->t('<br/><u>Proximity format should be in the following format: <strong>"40.73,-73.93<=5[unit]"</strong></u>, where the operator might be also: ><br>and [unit] should be one of the following key value:</u>@units_decodes.<br><u>Note:</u> Use dot (.) as decimal separator, and not comma (,), otherwise results won\'t be accurate.</strong>', [
'@units_decodes' => Markup::create($this
->unitsListMarkup()),
]);
}
public function query($group_by = FALSE) {
$this
->ensureMyTable();
$lat_alias = $this->realField . '_lat';
$lon_alias = $this->realField . '_lon';
try {
$values = $this
->getParsedReferenceLocation();
if (!empty($values)) {
$source_configuration = [
'origin' => [
'lat' => $values['lat'],
'lon' => $values['lon'],
],
];
$this->sourcePlugin = $this->proximitySourceManager
->createInstance('geofield_context_filter', $source_configuration);
$this->sourcePlugin
->setViewHandler($this);
$this->sourcePlugin
->setUnits($values['units']);
if ($haversine_options = $this->sourcePlugin
->getHaversineOptions()) {
$haversine_options['destination_latitude'] = $this->tableAlias . '.' . $lat_alias;
$haversine_options['destination_longitude'] = $this->tableAlias . '.' . $lon_alias;
$this
->operator($haversine_options, $values['distance'], $values['operator']);
}
}
} catch (\Exception $e) {
watchdog_exception('geofield', $e);
}
}
protected function operator($options, $distance, $operator) {
if (!empty($distance) && is_numeric($distance)) {
$query = $this->query;
$query
->addWhereExpression(0, geofield_haversine($options) . ' ' . $operator . ' ' . $distance);
}
}
public function getParsedReferenceLocation() {
static $values;
if (!isset($values)) {
preg_match('/^([0-9\\-.]+),+([0-9\\-.]+)([<>=]+)([0-9.]+)(.*$)/', trim($this
->getValue()), $values);
$values = is_array($values) && !empty($values) ? [
'lat' => isset($values[1]) && is_numeric($values[1]) && $values[1] >= -90 && $values[1] <= 90 ? floatval($values[1]) : FALSE,
'lon' => isset($values[2]) && is_numeric($values[2]) && $values[2] >= -180 && $values[2] <= 180 ? floatval($values[2]) : FALSE,
'operator' => isset($values[3]) && in_array($values[3], [
'<>',
'=',
'>=',
'<=',
'>',
'<',
]) ? $values[3] : '<=',
'distance' => isset($values[4]) ? floatval($values[4]) : FALSE,
'units' => isset($values[5]) && array_key_exists($values[5], $this->units) ? $this->units[$values[5]]['value'] : 'GEOFIELD_KILOMETERS',
] : FALSE;
}
return $values;
}
}