You are here

IpGeoLocPluginStyleMap.php in IP Geolocation Views & Maps 8

File

src/Plugin/views/style/IpGeoLocPluginStyleMap.php
View source
<?php

namespace Drupal\ip_geoloc\Plugin\views\style;

use Drupal\core\form\FormStateInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\Core\Extension\ModuleHandler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\ip_geoloc\Services\IpGeoLocAPI;
use Drupal\ip_geoloc\Services\IpGeoLocGlobal;
use Drupal\ip_geoloc\Services\IpGeoLocSession;
use Drupal\ip_geoloc\Services\IpGeoLocViewsPluginStyle;
use Drupal\Core\StringTranslation\TranslationManager;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Unicode;

/*require_once 'ip_geoloc_plugin_style.inc';*/

/**
 * Views Style plugin extension for Map.
 *
 * @ingroup views_style_plugins
 *
 * @ViewsStyle(
 *   id = "ip_geoloc_plugin_style",
 *   title = @Translation("Map (Google API, via IPGV&M)"),
 *   help = @Translation("Views Style plugin extension for Map."),
 *   theme = "ip_geoloc_map",
 *   display_types = { "normal" }
 * )
 */
class IpGeoLocPluginStyleMap extends StylePluginBase {

  /**
   * {@inheritdoc}
   */
  protected $usesGrouping = TRUE;

  /**
   * {@inheritdoc}
   */
  protected $usesFields = TRUE;

  /**
   * Plugin base constructor for dependency injection.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, IpGeoLocAPI $api, ModuleHandler $module_handler, IpGeoLocGlobal $ip_geoloc_global, TranslationManager $string_translation, IpGeoLocSession $ip_geoloc_session, IpGeoLocViewsPluginStyle $ip_geoloc_view_plugin_style, RequestStack $request_stack) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->api = $api;
    $this->module_handler = $module_handler;
    $this->ip_geoloc_global = $ip_geoloc_global;
    $this->string_translation = $string_translation;
    $this->session = $ip_geoloc_session;
    $this->view_plugin_style = $ip_geoloc_view_plugin_style;
    $this->request_stack = $request_stack;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('ip_geoloc.api'), $container
      ->get('module_handler'), $container
      ->get('ip_geoloc.global'), $container
      ->get('string_translation'), $container
      ->get('ip_geoloc.session'), $container
      ->get('ip_geoloc.views_plugin_style'), $container
      ->get('request_stack'));
  }

  /**
   * Set default Leaflet options.
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $latitude = $this->module_handler
      ->moduleExists('location') ? 'location_latitude' : 'ip_geoloc_latitude';

    // For field-based modules.
    $longitude = $this->module_handler
      ->moduleExists('location') ? 'location_longitude' : ($latitude == 'ip_geoloc_latitude' ? 'ip_geoloc_longitude' : $latitude);
    $options['ip_geoloc_views_plugin_latitude'] = [
      'default' => $latitude,
    ];
    $options['ip_geoloc_views_plugin_longitude'] = [
      'default' => $longitude,
    ];
    $options['differentiator'] = [
      'contains' => [
        'differentiator_field' => [
          'default' => '',
        ],
      ],
    ];
    $options['default_marker_color'] = [
      'default' => '<none>',
    ];
    $options['center_option'] = [
      'default' => IP_GEOLOC_MAP_CENTER_ON_FIRST_LOCATION,
    ];
    $options['visitor_marker'] = [
      'default' => '<none>',
    ];
    $options['gps_roles'] = [
      'default' => [
        DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID,
        DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID,
      ],
    ];
    $options['map_options'] = [
      'default' => '',
    ];
    $options['map_div_style'] = [
      'default' => '',
    ];
    $options['empty_map_center'] = [
      'default' => '',
    ];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
    $form_state
      ->set('renderer', 'google');
    $this->view_plugin_style
      ->pluginStyleBulkOfForm($this, $form, $form_state);

    //ip_geoloc_plugin_style_bulk_of_form($this, $form, $form_state);
    $form['map_options'] = [
      '#title' => t('Map options'),
      '#type' => 'textfield',
      '#size' => 127,
      '#maxlength' => 511,
      '#default_value' => $this->options['map_options'],
      '#description' => t("If left blank, the default ") . IP_GEOLOC_RECENT_VISITORS_MAP_OPTIONS . t(" will produce a world map zoomed in to level 2. A list of map options can be found <a href='") . IP_GEOLOC_DOC_GOOGLE_MAP_OPTIONS . t("'>here</a>. Remember to separate options with comma's, not semi-colons, and make sure your (double) quotes match.<br/>These options apply a grey hue to all roads:<br/>") . IP_GEOLOC_EXAMPLE_MAP_OPTIONS,
      '#weight' => 35,
    ];
    $form['default_marker_color'] = [
      '#title' => t('Marker color'),
      '#type' => 'textfield',
      '#size' => 127,
      '#maxlength' => 511,
      '#default_value' => $this->options['default_marker_color'],
      '#description' => t("Add the default marker color, by default google maps style. The available values are: blue,drupal,green,grey,light-blue,orange,pink,purple,red,red-cluster,red+dot,red+square,white,yellow.png"),
      '#weight' => 36,
    ];
    $form['map_div_style'] = [
      '#title' => t('Map style (CSS attributes)'),
      '#type' => 'textfield',
      '#size' => 127,
      '#maxlength' => 511,
      '#default_value' => $this->options['map_div_style'],
      '#description' => t('If left blank, the default ') . IP_GEOLOC_MAP_DIV_DEFAULT_STYLE . t(' will result in a map of 300 pixels high, with a width bounded by the element that contains it. Separate style settings with semi-colons. Do not enter quotes or equal signs.'),
      '#weight' => 37,
    ];
    $form['visitor_marker'] = [
      '#title' => t('Visitor marker color'),
      '#type' => 'textfield',
      '#size' => 6,
      '#default_value' => $this->options['visitor_marker'],
      '#description' => t("Show visitor marker in the color specified. %color_code is bright green. Note that an additional web service call will be made to retrieve the marker image, unless this field is left blank, which will result in a standard red marker. Enter <em>&lt;none&gt;</em> if you do not wish to display the visitor's current location.", [
        '%color_code' => '00FF00',
      ]),
      '#weight' => 90,
    ];
    $form['gps_roles'] = [
      '#title' => t('Roles for which HTML5-style visitor location retrieval is to be applied'),
      '#type' => 'checkboxes',
      '#default_value' => $this->options['gps_roles'],
      '#options' => user_role_names(),
      '#description' => t('This is subject to the visitor willing to share their location when prompted by their browser. If they decline, or if their roles aren\'t ticked, an IP address lookup will be attempted instead. In case the lookup fails, for instance because you have not enabled Smart IP or GeoIP, make sure you specify "centerLat" and "centerLng" in the <strong>Map options</strong> below to avoid an empty canvas.'),
      '#weight' => 95,
    ];
    return $form;
  }

  /**
   * Validate the options form.
   */
  public function validateOptionsForm(&$form, FormStateInterface $form_state) {
    $this->view_plugin_style
      ->pluginStyleBulkOfFormValidate($form, $form_state);
  }

  /**
   * Transform the View result in a list of markers and render these on a map.
   */
  public function render() {
    if (!empty($this->view->live_preview)) {
      return t('The preview function is incompatible with Google Maps so cannot be used. Please visit the page path or block to view your map.');
    }
    $this->view_plugin_style
      ->pluginStyleRenderFields($this);
    $locations = $this->view_plugin_style
      ->pluginStyleExtractLocations($this);
    $map_options = empty($this->options['map_options']) ? IP_GEOLOC_RECENT_VISITORS_MAP_OPTIONS : $this->options['map_options'];
    $map_div_style = empty($this->options['map_div_style']) ? IP_GEOLOC_MAP_DIV_DEFAULT_STYLE : SafeMarkup::checkPlain($this->options['map_div_style']);
    $marker_color = empty($this->options['default_marker_color']) ? '' : $this->options['default_marker_color'];
    if (empty($this->options['visitor_marker'])) {

      // Default to standard red marker.
      $visitor_marker = TRUE;
    }
    else {
      $visitor_marker = trim($this->options['visitor_marker']);
      $visitor_marker = strpos($visitor_marker, 'none') === FALSE ? SafeMarkup::checkPlain($visitor_marker) : FALSE;
    }
    $center_option = !isset($this->options['center_option']) ? IP_GEOLOC_MAP_CENTER_ON_FIRST_LOCATION : $this->options['center_option'];
    $center_latlng = [];
    if ($visitor_marker || $center_option == IP_GEOLOC_MAP_CENTER_ON_VISITOR) {

      // Perform database IP lookup as backup/replacement for HTML5 location
      // Visitor may be moving so ignore existing lat/long.
      $resample = TRUE;

      // Do not store lat/long and city as it will obliterate the
      // reverse-geocoded one.
      $store = FALSE;

      // We only need lat/long, not full street address.
      $reverse_geocode = FALSE;
      $visitor_location = $this->api
        ->getLocationByIp($this->request_stack
        ->getCurrentRequest()
        ->getClientIp(), $resample, $store, $reverse_geocode);
      if (isset($visitor_location['latitude']) && isset($visitor_location['longitude'])) {
        $center_latlng = [
          $visitor_location['latitude'],
          $visitor_location['longitude'],
        ];
      }
    }
    if (empty($locations)) {
      $ll = trim($this->options['empty_map_center']);
      if (empty($ll)) {

        // No map whatsoever.
        return;
      }
      if ($ll != t('visitor')) {

        // Empty map centered on coordinates provided.
        list($center_lat, $center_lng) = preg_split("/[\\s,]+/", $ll);
      }
    }
    elseif ($center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS || $center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS_WEIGHTED) {
      list($center_lat, $center_lng) = $this->api
        ->centerOfLocations($locations, $center_option == IP_GEOLOC_MAP_CENTER_OF_LOCATIONS_WEIGHTED);
    }
    if (isset($center_lat) && isset($center_lng)) {
      $map_options = Unicode::substr($map_options, 0, strrpos($map_options, '}'));
      $map_options = $map_options . ', "centerLat":' . $center_lat . ', "centerLng":' . $center_lng . '}';
    }
    $account = \Drupal::currentUser();
    $gps_roles = empty($this->options['gps_roles']) ? [
      DRUPAL_ANONYMOUS_RID,
      DRUPAL_AUTHENTICATED_RID,
    ] : $this->options['gps_roles'];
    $gps_roles_applicable = array_intersect($gps_roles, array_keys($account->roles));

    // drupal_add_js(IP_GEOLOC_GOOGLE_MAPS, ['type' => 'external', 'group' => JS_LIBRARY]);
    // drupal_add_js(drupal_get_path('module', 'ip_geoloc') . '/js/ip_geoloc_gmap_multi_visitor.js');
    if (!isset($map_options)) {
      $map_options = IP_GEOLOC_RECENT_VISITORS_MAP_OPTIONS;
    }
    $div_id = 'ip-geoloc-map-of-view-' . $this->view->storage
      ->id() . '-' . $this->view->current_display;
    return $this->api
      ->outputMapMultiLocation($locations, $div_id, $map_options, $map_div_style, $marker_color, $visitor_marker, $center_option, $center_latlng, !empty($gps_roles_applicable));
  }

  /**
   * Sets rendered field definition.
   */
  public function setRenderedFields($rendered_fields = []) {
    $this->rendered_fields = $rendered_fields;
  }

  /**
   * Gets rendered field definition.
   */
  public function getRenderedFields() {
    return $this->rendered_fields;
  }

}

Classes

Namesort descending Description
IpGeoLocPluginStyleMap Views Style plugin extension for Map.