You are here

trait GeofieldMapFieldTrait in Geofield Map 8

Same name and namespace in other branches
  1. 8.2 src/GeofieldMapFieldTrait.php \Drupal\geofield_map\GeofieldMapFieldTrait

Class GeofieldMapFieldTrait.

Provide common functions for Geofield Map fields.

@package Drupal\geofield_map

Hierarchy

3 files declare their use of GeofieldMapFieldTrait
GeofieldGoogleMapFormatter.php in src/Plugin/Field/FieldFormatter/GeofieldGoogleMapFormatter.php
GeofieldGoogleMapViewStyle.php in src/Plugin/views/style/GeofieldGoogleMapViewStyle.php
GeofieldMapWidget.php in src/Plugin/Field/FieldWidget/GeofieldMapWidget.php

File

src/GeofieldMapFieldTrait.php, line 17

Namespace

Drupal\geofield_map
View source
trait GeofieldMapFieldTrait {

  /**
   * Google Map Types Options.
   *
   * @var array
   */
  protected $gMapTypesOptions = [
    'roadmap' => 'Roadmap',
    'satellite' => 'Satellite',
    'hybrid' => 'Hybrid',
    'terrain' => 'Terrain',
  ];

  /**
   * Google Map Types Options.
   *
   * @var array
   */
  protected $infowindowFieldTypesOptions = [
    'string_long',
    'string',
    'text',
    'text_long',
    "text_with_summary",
  ];
  protected $customMapStylePlaceholder = '[{"elementType":"geometry","stylers":[{"color":"#1d2c4d"}]},{"elementType":"labels.text.fill","stylers":[{"color":"#8ec3b9"}]},{"elementType":"labels.text.stroke","stylers":[{"color":"#1a3646"}]},{"featureType":"administrative.country","elementType":"geometry.stroke","stylers":[{"color":"#4b6878"}]},{"featureType":"administrative.province","elementType":"geometry.stroke","stylers":[{"color":"#4b6878"}]},{"featureType":"water","elementType":"geometry","stylers":[{"color":"#0e1626"}]},{"featureType":"water","elementType":"labels.text.fill","stylers":[{"color":"#4e6d70"}]}]';

  /**
   * The Link generator Service.
   *
   * @var \Drupal\Core\Utility\LinkGeneratorInterface $this->link
   */

  /**
   * Get the GMap Api Key from the geofield_map settings/configuration.
   *
   * @return string
   *   The GMap Api Key
   */
  private function getGmapApiKey() {

    /* @var \Drupal\Core\Config\ConfigFactoryInterface $config */
    $config = $this->config;
    $geofield_map_settings = $config
      ->getEditable('geofield_map.settings');
    $gmap_api_key = $geofield_map_settings
      ->get('gmap_api_key');

    // In the first release of Geofield_Map the google_api_key was stored in
    // the specific Field Widget settings.
    // So we try and copy into the geofield_map.settings config, in the case.
    if (method_exists(get_class($this), 'getSetting') && !empty($this
      ->getSetting('map_google_api_key')) && empty($gmap_api_key)) {
      $gmap_api_key = $this
        ->getSetting('map_google_api_key');
      $geofield_map_settings
        ->set('gmap_api_key', $gmap_api_key)
        ->save();
    }
    return $gmap_api_key;
  }

  /**
   * Get the Default Settings.
   *
   * @return array
   *   The default settings.
   */
  public static function getDefaultSettings() {
    return [
      'gmap_api_key' => '',
      'map_dimensions' => [
        'width' => '100%',
        'height' => '450px',
      ],
      'map_empty' => [
        'empty_behaviour' => '0',
        'empty_message' => t('No Geofield Value entered for this field'),
      ],
      'map_center' => [
        'lat' => '42',
        'lon' => '12.5',
        'center_force' => 0,
      ],
      'map_zoom_and_pan' => [
        'zoom' => [
          'initial' => 6,
          'force' => 0,
          'min' => 1,
          'max' => 22,
        ],
        'scrollwheel' => 1,
        'draggable' => 1,
        'map_reset' => 0,
      ],
      'map_controls' => [
        'disable_default_ui' => 0,
        'zoom_control' => 1,
        'map_type_id' => 'roadmap',
        'map_type_control' => 1,
        'map_type_control_options_type_ids' => [
          'roadmap' => 'roadmap',
          'satellite' => 'satellite',
          'hybrid' => 'hybrid',
          'terrain' => 'terrain',
        ],
        'scale_control' => 1,
        'street_view_control' => 1,
        'fullscreen_control' => 1,
      ],
      'map_marker_and_infowindow' => [
        'icon_image_path' => '',
        'infowindow_field' => 'title',
        'multivalue_split' => 0,
        'force_open' => 0,
      ],
      'map_oms' => [
        'map_oms_control' => 1,
        'map_oms_options' => '{"markersWontMove": "true", "markersWontHide": "true", "basicFormatEvents": "true", "nearbyDistance": 3}',
      ],
      'map_additional_options' => '',
      'custom_style_map' => [
        'custom_style_control' => 0,
        'custom_style_name' => '',
        'custom_style_options' => '',
        'custom_style_default' => 0,
      ],
      'map_markercluster' => [
        'markercluster_control' => 0,
        'markercluster_additional_options' => '',
      ],
    ];
  }

  /**
   * Generate the Google Map Settings Form.
   *
   * @param array $form
   *   The form where the settings form is being included in.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array $settings
   *   Form settings.
   * @param array $default_settings
   *   Default settings.
   *
   * @return array
   *   The GMap Settings Form*/
  public function generateGmapSettingsForm(array $form, FormStateInterface $form_state, array $settings, array $default_settings) {
    $elements = [];

    // Attach Geofield Map Library.
    $elements['#attached']['library'] = [
      'geofield_map/geofield_map_general',
    ];

    // Set Google Api Key Element.
    $this
      ->setMapGoogleApiKeyElement($elements);

    // Set Map Dimension Element.
    $this
      ->setMapDimensionsElement($settings, $elements);

    // Set Map Empty Options Element.
    $this
      ->setMapEmptyElement($settings, $elements);
    $elements['gmaps_api_link_markup'] = [
      '#markup' => $this
        ->t('The following settings comply with the @gmaps_api_link.', [
        '@gmaps_api_link' => $this->link
          ->generate($this
          ->t('Google Maps JavaScript API Library'), Url::fromUri('https://developers.google.com/maps/documentation/javascript', [
          'absolute' => TRUE,
          'attributes' => [
            'target' => 'blank',
          ],
        ])),
      ]),
    ];

    // Set Map Center Element.
    $this
      ->setMapCenterElement($settings, $elements);

    // Set Map Zoom and Pan Element.
    $this
      ->setMapZoomAndPanElement($settings, $default_settings, $elements);

    // Set Map Control Element.
    $this
      ->setMapControlsElement($settings, $elements);

    // Set Map Marker and Infowindow Element.
    $this
      ->setMapMarkerAndInfowindowElement($form, $settings, $elements);

    // Set Map Additional Options Element.
    $this
      ->setMapAdditionalOptionsElement($settings, $elements);

    // Set Overlapping Marker Spiderfier Element.
    $this
      ->setMapOmsElement($settings, $default_settings, $elements);

    // Set Custom Map Style Element.
    $this
      ->setCustomStyleMapElement($settings, $elements);

    // Set Map Marker Cluster Element.
    $this
      ->setMapMarkerclusterElement($settings, $elements);
    return $elements;
  }

  /**
   * Form element validation handler for a Map Zoom level.
   *
   * {@inheritdoc}
   */
  public static function zoomLevelValidate($element, FormStateInterface &$form_state) {

    // Get to the actual values in a form tree.
    $parents = $element['#parents'];
    $values = $form_state
      ->getValues();
    for ($i = 0; $i < count($parents) - 1; $i++) {
      $values = $values[$parents[$i]];
    }

    // Check the initial map zoom level.
    $zoom = $element['#value'];
    $min_zoom = $values['min'];
    $max_zoom = $values['max'];
    if ($zoom < $min_zoom || $zoom > $max_zoom) {
      $form_state
        ->setError($element, t('The @zoom_field should be between the Minimum and the Maximum Zoom levels.', [
        '@zoom_field' => $element['#title'],
      ]));
    }
  }

  /**
   * Form element validation handler for the Map Max Zoom level.
   *
   * {@inheritdoc}
   */
  public static function maxZoomLevelValidate($element, FormStateInterface &$form_state) {

    // Get to the actual values in a form tree.
    $parents = $element['#parents'];
    $values = $form_state
      ->getValues();
    for ($i = 0; $i < count($parents) - 1; $i++) {
      $values = $values[$parents[$i]];
    }

    // Check the max zoom level.
    $min_zoom = $values['min'];
    $max_zoom = $element['#value'];
    if ($max_zoom && $max_zoom <= $min_zoom) {
      $form_state
        ->setError($element, t('The Max Zoom level should be above the Minimum Zoom level.'));
    }
  }

  /**
   * Form element validation handler for a Custom Map Style Name Required.
   *
   * {@inheritdoc}
   */
  public static function customMapStyleValidate($element, FormStateInterface &$form_state) {

    // Get to the actual values in a form tree.
    $parents = $element['#parents'];
    $values = $form_state
      ->getValues();
    for ($i = 0; $i < count($parents) - 1; $i++) {
      $values = $values[$parents[$i]];
    }
    if ($values['custom_style_control'] && empty($element['#value'])) {
      $form_state
        ->setError($element, t('The @field cannot be empty.', [
        '@field' => $element['#title'],
      ]));
    }
  }

  /**
   * Form element json format validation handler.
   *
   * {@inheritdoc}
   */
  public static function jsonValidate($element, FormStateInterface &$form_state) {
    $element_values_array = JSON::decode($element['#value']);

    // Check the jsonValue.
    if (!empty($element['#value']) && $element_values_array == NULL) {
      $form_state
        ->setError($element, t('The @field field is not valid Json Format.', [
        '@field' => $element['#title'],
      ]));
    }
    elseif (!empty($element['#value'])) {
      $form_state
        ->setValueForElement($element, JSON::encode($element_values_array));
    }
  }

  /**
   * Form element url format validation handler.
   *
   * {@inheritdoc}
   */
  public static function urlValidate($element, FormStateInterface &$form_state) {
    $path = $element['#value'];

    // Check the jsonValue.
    if (UrlHelper::isExternal($path) && !UrlHelper::isValid($path, TRUE)) {
      $form_state
        ->setError($element, t('The @field field is not valid Url Format.', [
        '@field' => $element['#title'],
      ]));
    }
    elseif (!UrlHelper::isExternal($path)) {
      $path = Url::fromUri('base:' . $path, [
        'absolute' => TRUE,
      ])
        ->toString();
      if (!UrlHelper::isValid($path)) {
        $form_state
          ->setError($element, t('The @field field is not valid internal Drupal path.', [
          '@field' => $element['#title'],
        ]));
      }
    }
  }

  /**
   * Pre Process the MapSettings.
   *
   * Performs some preprocess on the maps settings before sending to js.
   *
   * @param array $map_settings
   *   The map settings.
   */
  protected function preProcessMapSettings(array &$map_settings) {

    // Set the gmap_api_key as map settings.
    $map_settings['gmap_api_key'] = $this
      ->getGmapApiKey();

    // Transform into simple array values the map_type_control_options_type_ids.
    $map_settings['map_controls']['map_type_control_options_type_ids'] = array_keys(array_filter($map_settings['map_controls']['map_type_control_options_type_ids'], function ($value) {
      return $value !== 0;
    }));

    // Generate Absolute icon_image_path, if it is not.
    $icon_image_path = $map_settings['map_marker_and_infowindow']['icon_image_path'];
    if (!empty($icon_image_path) && !UrlHelper::isExternal($map_settings['map_marker_and_infowindow']['icon_image_path'])) {
      $map_settings['map_marker_and_infowindow']['icon_image_path'] = Url::fromUri('base:' . $icon_image_path, [
        'absolute' => TRUE,
      ])
        ->toString();
    }
  }

  /**
   * Transform Geofield data into Geojson features.
   *
   * @param mixed $items
   *   The Geofield Data Values.
   * @param string $description
   *   The description value.
   * @param mixed $additional_data
   *   Additional data to be added to the feature properties, i.e.
   *   GeofieldGoogleMapViewStyle will add row fields (already rendered).
   *
   * @return array
   *   The data array for the current feature, including Geojson and additional
   *   data.
   */
  protected function getGeoJsonData($items, $description = NULL, $additional_data = NULL) {
    $data = [];
    foreach ($items as $delta => $item) {

      /* @var \Point $geometry */
      if (is_a($item, '\\Drupal\\geofield\\Plugin\\Field\\FieldType\\GeofieldItem') && isset($item->value)) {
        $geometry = $this->geoPhpWrapper
          ->load($item->value);
      }
      elseif (preg_match('/^(POINT).*\\(.*.*\\)$/', $item)) {
        $geometry = $this->geoPhpWrapper
          ->load($item);
      }
      if (isset($geometry)) {
        $datum = [
          "type" => "Feature",
          "geometry" => json_decode($geometry
            ->out('json')),
        ];
        $datum['properties'] = [
          // If a multivalue field value with the same index exist, use this,
          // else use the first item as fallback.
          'description' => isset($description[$delta]) ? $description[$delta] : (isset($description[0]) ? $description[0] : NULL),
          'data' => $additional_data,
        ];
        $data[] = $datum;
      }
    }
    return $data;
  }

  /**
   * Set Map Google Api Key Element.
   *
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapGoogleApiKeyElement(array &$elements) {
    $gmap_api_key = $this
      ->getGmapApiKey();

    // Define the Google Maps API Key value message markup.
    if (!empty($gmap_api_key)) {
      $map_google_api_key_value = $this
        ->t('<strong>Gmap Api Key:</strong> @gmaps_api_key_link<br><div class="description">A valid Gmap Api Key is needed anyway for the Widget Geocode and ReverseGeocode functionalities (provided by the Google Map Geocoder)</div>', [
        '@gmaps_api_key_link' => $this->link
          ->generate($gmap_api_key, Url::fromRoute('geofield_map.settings', [], [
          'query' => [
            'destination' => Url::fromRoute('<current>')
              ->toString(),
          ],
        ])),
      ]);
    }
    else {
      $map_google_api_key_value = $this
        ->t("<span class='geofield-map-warning'>Gmap Api Key missing.<br>Google Maps functionality may not be available. </span>@settings_page_link", [
        '@settings_page_link' => $this->link
          ->generate($this
          ->t('Set it in the Geofield Map Configuration Page'), Url::fromRoute('geofield_map.settings', [], [
          'query' => [
            'destination' => Url::fromRoute('<current>')
              ->toString(),
          ],
        ])),
      ]);
    }
    $elements['map_google_api_key'] = [
      '#type' => 'html_tag',
      '#tag' => 'div',
      '#value' => $map_google_api_key_value,
    ];
  }

  /**
   * Set Map Dimension Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapDimensionsElement(array $settings, array &$elements) {
    $elements['map_dimensions'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Map Dimensions'),
    ];
    $elements['map_dimensions']['width'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Map width'),
      '#default_value' => $settings['map_dimensions']['width'],
      '#size' => 25,
      '#maxlength' => 25,
      '#description' => $this
        ->t('The default width of a Google map, as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>'),
      '#required' => TRUE,
    ];
    $elements['map_dimensions']['height'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Map height'),
      '#default_value' => $settings['map_dimensions']['height'],
      '#size' => 25,
      '#maxlength' => 25,
      '#description' => $this
        ->t('The default height of a Google map, as a CSS length or percentage. Examples: <em>50px</em>, <em>5em</em>, <em>2.5in</em>, <em>95%</em>'),
      '#required' => TRUE,
    ];
  }

  /**
   * Set Map Empty Options Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapEmptyElement(array $settings, array &$elements) {
    $elements['map_empty'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Which behaviour for the empty map?'),
      '#description' => $this
        ->t('If there are no entries on the map, what should be the output of field?'),
    ];
    if (isset($this->fieldDefinition)) {
      $elements['map_empty']['empty_behaviour'] = [
        '#type' => 'select',
        '#title' => $this
          ->t('Behaviour'),
        '#default_value' => $settings['map_empty']['empty_behaviour'],
        '#options' => $this->emptyMapOptions,
      ];
      $elements['map_empty']['empty_message'] = [
        '#type' => 'textfield',
        '#title' => $this
          ->t('Empty Map Message'),
        '#description' => $this
          ->t('The message that should be rendered instead on an empty map.'),
        '#default_value' => $settings['map_empty']['empty_message'],
        '#states' => [
          'visible' => [
            ':input[name="fields[' . $this->fieldDefinition
              ->getName() . '][settings_edit_form][settings][map_empty][empty_behaviour]"]' => [
              'value' => '1',
            ],
          ],
        ],
      ];
    }
    else {
      $elements['map_empty']['empty_behaviour'] = [
        '#type' => 'select',
        '#title' => $this
          ->t('Behaviour'),
        '#default_value' => $settings['map_empty']['empty_behaviour'],
        '#options' => $this->emptyMapOptions,
      ];
    }
  }

  /**
   * Set Map Center Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapCenterElement(array $settings, array &$elements) {
    $elements['map_center'] = [
      '#type' => 'geofield_latlon',
      '#title' => $this
        ->t('Default Center'),
      '#default_value' => $settings['map_center'],
      '#size' => 25,
      '#description' => $this
        ->t('If there are no entries on the map, where should the map be centered?'),
      '#geolocation' => TRUE,
      'center_force' => [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Force the Map Center'),
        '#description' => $this
          ->t('The Map will generally focus center on the input Geofields.<br>This option will instead force the Map Center notwithstanding the Geofield Values'),
        '#default_value' => $settings['map_center']['center_force'],
        '#return_value' => 1,
      ],
    ];
  }

  /**
   * Set Map Zoom and Pan Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $default_settings
   *   The default_settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapZoomAndPanElement(array $settings, array $default_settings, array &$elements) {
    $elements['map_zoom_and_pan'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Map Zoom and Pan'),
    ];
    $elements['map_zoom_and_pan']['zoom'] = [
      'initial' => [
        '#type' => 'number',
        '#min' => $settings['map_zoom_and_pan']['zoom']['min'],
        '#max' => $settings['map_zoom_and_pan']['zoom']['max'],
        '#title' => $this
          ->t('Start Zoom'),
        '#default_value' => $settings['map_zoom_and_pan']['zoom']['initial'],
        '#description' => $this
          ->t('The Initial Zoom level of the Google Map.'),
        '#element_validate' => [
          [
            get_class($this),
            'zoomLevelValidate',
          ],
        ],
      ],
      'force' => [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Force the Start Zoom'),
        '#description' => $this
          ->t('In case of multiple GeoMarkers, the Map will naturally focus zoom on the input Geofields bounds.<br>This option will instead force the Map Zoom on the input Start Zoom value'),
        '#default_value' => $settings['map_zoom_and_pan']['zoom']['force'],
        '#return_value' => 1,
      ],
      'min' => [
        '#type' => 'number',
        '#min' => isset($default_settings['map_zoom_and_pan']['default']) ? $default_settings['map_zoom_and_pan']['default']['zoom']['min'] : $default_settings['map_zoom_and_pan']['zoom']['min'],
        '#max' => $settings['map_zoom_and_pan']['zoom']['max'],
        '#title' => $this
          ->t('Min Zoom Level'),
        '#default_value' => $settings['map_zoom_and_pan']['zoom']['min'],
        '#description' => $this
          ->t('The Minimum Zoom level for the Map.'),
      ],
      'max' => [
        '#type' => 'number',
        '#min' => $settings['map_zoom_and_pan']['zoom']['min'],
        '#max' => isset($default_settings['map_zoom_and_pan']['default']) ? $default_settings['map_zoom_and_pan']['default']['zoom']['max'] : $default_settings['map_zoom_and_pan']['zoom']['max'],
        '#title' => $this
          ->t('Max Zoom Level'),
        '#default_value' => $settings['map_zoom_and_pan']['zoom']['max'],
        '#description' => $this
          ->t('The Maximum Zoom level for the Map.'),
        '#element_validate' => [
          [
            get_class($this),
            'maxZoomLevelValidate',
          ],
        ],
      ],
    ];
    $elements['map_zoom_and_pan']['scrollwheel'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Scrollwheel'),
      '#description' => $this
        ->t('Enable scrollwheel zooming'),
      '#default_value' => $settings['map_zoom_and_pan']['scrollwheel'],
      '#return_value' => 1,
    ];
    $elements['map_zoom_and_pan']['draggable'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Draggable'),
      '#description' => $this
        ->t('Enable dragging/panning on the map'),
      '#default_value' => $settings['map_zoom_and_pan']['draggable'],
      '#return_value' => 1,
    ];
    $elements['map_zoom_and_pan']['map_reset'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enable Map Reset Control'),
      '#description' => $this
        ->t('This will show a "Reset Map" button to reset the Map to its initial center & zoom state'),
      '#default_value' => isset($settings['map_zoom_and_pan']['map_reset']) ? $settings['map_zoom_and_pan']['map_reset'] : FALSE,
      '#return_value' => 1,
    ];
  }

  /**
   * Set Map Control Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapControlsElement(array $settings, array &$elements) {
    if (isset($this->fieldDefinition)) {
      $disable_default_ui_selector = ':input[name="fields[' . $this->fieldDefinition
        ->getName() . '][settings_edit_form][settings][map_controls][disable_default_ui]"]';
    }
    else {
      $disable_default_ui_selector = ':input[name="style_options[map_controls][disable_default_ui]"]';
    }
    $elements['map_controls'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Map Controls'),
    ];
    $elements['map_controls']['disable_default_ui'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Disable Default UI'),
      '#description' => $this
        ->t('This property disables any automatic UI behavior and Control from the Google Map'),
      '#default_value' => $settings['map_controls']['disable_default_ui'],
      '#return_value' => 1,
    ];
    $elements['map_controls']['zoom_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Zoom Control'),
      '#description' => $this
        ->t('The enabled/disabled state of the Zoom control.'),
      '#default_value' => $settings['map_controls']['zoom_control'],
      '#return_value' => 1,
      '#states' => [
        'visible' => [
          $disable_default_ui_selector => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];
    $elements['map_controls']['map_type_id'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Default Map Type'),
      '#default_value' => $settings['map_controls']['map_type_id'],
      '#options' => $this->gMapTypesOptions,
    ];
    $elements['map_controls']['map_type_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enabled Map Type Control'),
      '#description' => $this
        ->t('The initial enabled/disabled state of the Map type control.'),
      '#default_value' => $settings['map_controls']['map_type_control'],
      '#return_value' => 1,
      '#states' => [
        'visible' => [
          $disable_default_ui_selector => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];
    $elements['map_controls']['map_type_control_options_type_ids'] = [
      '#type' => 'checkboxes',
      '#title' => $this
        ->t('The enabled Map Types'),
      '#description' => $this
        ->t('The Map Types that will be available in the Map Type Control.'),
      '#default_value' => $settings['map_controls']['map_type_control_options_type_ids'],
      '#options' => $this->gMapTypesOptions,
      '#return_value' => 1,
    ];
    if (isset($this->fieldDefinition)) {
      $elements['map_controls']['map_type_control_options_type_ids']['#states'] = [
        'invisible' => [
          [
            ':input[name="fields[' . $this->fieldDefinition
              ->getName() . '][settings_edit_form][settings][map_controls][map_type_control]"]' => [
              'checked' => FALSE,
            ],
          ],
          [
            $disable_default_ui_selector => [
              'checked' => TRUE,
            ],
          ],
        ],
      ];
    }
    else {
      $elements['map_controls']['map_type_control_options_type_ids']['#states'] = [
        'invisible' => [
          [
            ':input[name="style_options[map_controls][map_type_control]"]' => [
              'checked' => FALSE,
            ],
          ],
          [
            $disable_default_ui_selector => [
              'checked' => TRUE,
            ],
          ],
        ],
      ];
    }
    $elements['map_controls']['scale_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Scale Control'),
      '#description' => $this
        ->t('Show map scale'),
      '#default_value' => $settings['map_controls']['scale_control'],
      '#return_value' => 1,
      '#states' => [
        'visible' => [
          $disable_default_ui_selector => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];
    $elements['map_controls']['street_view_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Streetview Control'),
      '#description' => $this
        ->t('Enable the Street View functionality on the Map.'),
      '#default_value' => $settings['map_controls']['street_view_control'],
      '#return_value' => 1,
      '#states' => [
        'visible' => [
          $disable_default_ui_selector => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];
    $elements['map_controls']['fullscreen_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Fullscreen Control'),
      '#description' => $this
        ->t('Enable the Fullscreen View of the Map.'),
      '#default_value' => $settings['map_controls']['fullscreen_control'],
      '#return_value' => 1,
      '#states' => [
        'visible' => [
          $disable_default_ui_selector => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];
  }

  /**
   * Set Map Marker and Infowindow Element.
   *
   * @param array $form
   *   The Form array.
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapMarkerAndInfowindowElement(array $form, array $settings, array &$elements) {

    // Get the configurations of possible entity fields.
    $fields_configurations = $this->entityFieldManager
      ->getFieldStorageDefinitions('node');
    $elements['map_marker_and_infowindow'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Map Marker and Infowindow'),
    ];
    $elements['map_marker_and_infowindow']['icon_image_path'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Icon Image'),
      '#size' => '120',
      '#description' => $this
        ->t('Input the Specific Icon Image path (absolute path, or relative to the Drupal site root prefixed with a trailing hash). If not set, or not found/loadable, the Default Google Marker will be used.'),
      '#default_value' => $settings['map_marker_and_infowindow']['icon_image_path'],
      '#placeholder' => 'modules/custom/geofield_map/images/beachflag.png',
      '#element_validate' => [
        [
          get_class($this),
          'urlValidate',
        ],
      ],
    ];
    $multivalue_fields_states = [];
    $infowindow_fields_options = [];
    foreach ($this->infowindowFieldTypesOptions as $field_type) {
      $infowindow_fields_options = array_merge_recursive($infowindow_fields_options, $this->entityFieldManager
        ->getFieldMapByFieldType($field_type));
    }

    // In case it is a Field Formatter.
    if (isset($this->fieldDefinition)) {
      $desc_options = [
        '0' => $this
          ->t('- Any - No Infowindow'),
        'title' => $this
          ->t('- Title -'),
      ];

      // Get the Cardinality set for the Formatter Field.
      $field_cardinality = $this->fieldDefinition
        ->getFieldStorageDefinition()
        ->getCardinality();
      foreach ($infowindow_fields_options[$form['#entity_type']] as $k => $field) {
        if (!empty(array_intersect($field['bundles'], [
          $form['#bundle'],
        ])) && !in_array($k, [
          'title',
          'revision_log',
        ])) {
          $desc_options[$k] = $k;

          /* @var \\Drupal\Core\Field\BaseFieldDefinition $fields_configurations[$k] */
          if ($field_cardinality !== 1 && (isset($fields_configurations[$k]) && $fields_configurations[$k]
            ->getCardinality() !== 1)) {
            $multivalue_fields_states[] = [
              'value' => $k,
            ];
          }
        }
      }
      $desc_options['#rendered_entity'] = $this
        ->t('- Rendered @entity entity -', [
        '@entity' => $form['#entity_type'],
      ]);
      $info_window_source_options = $desc_options;
    }
    else {
      $info_window_source_options = isset($settings['infowindow_content_options']) ? $settings['infowindow_content_options'] : [];
      foreach ($info_window_source_options as $k => $field) {

        /* @var \\Drupal\Core\Field\BaseFieldDefinition $fields_configurations[$k] */
        if (array_key_exists($k, $fields_configurations) && $fields_configurations[$k]
          ->getCardinality() !== 1) {
          $multivalue_fields_states[] = [
            'value' => $k,
          ];
        }
        if (array_key_exists($k, $fields_configurations) && $fields_configurations[$k]
          ->getCardinality() !== 1) {
          $multivalue_fields_states[] = [
            'value' => $k,
          ];
        }

        // Remove the fields options that are not string/text type fields
        // of the view entity type.
        if (isset($this->entityType) && substr($k, 0, 5) == 'field' && !array_key_exists($k, $infowindow_fields_options[$this->entityType])) {
          unset($info_window_source_options[$k]);
        }
      }
    }
    if (!empty($info_window_source_options)) {
      $elements['map_marker_and_infowindow']['infowindow_field'] = [
        '#type' => 'select',
        '#title' => $this
          ->t('Marker Infowindow Content from'),
        '#description' => $this
          ->t('Choose an existing string/text type field from which populate the Marker Infowindow'),
        '#options' => $info_window_source_options,
        '#default_value' => $settings['map_marker_and_infowindow']['infowindow_field'],
      ];
    }
    $elements['map_marker_and_infowindow']['multivalue_split'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Multivalue Field Split (<u>A Multivalue Field as been selected for the Infowindow Content)</u>'),
      '#description' => $this
        ->t('If checked, each field value will be split into each matching infowindow, following the same progressive order<br>(the first value of the field will be used otherwise, or as fallback in case of no match)'),
      '#default_value' => !empty($settings['map_marker_and_infowindow']['multivalue_split']) ? $settings['map_marker_and_infowindow']['multivalue_split'] : 0,
      '#return_value' => 1,
    ];
    if (isset($this->fieldDefinition)) {
      $elements['map_marker_and_infowindow']['multivalue_split']['#description'] = $this
        ->t('If checked, each field value will be split into each matching infowindow / geofield, following the same progressive order<br>(the first value of the field will be used otherwise, or as fallback in case of no match)');
      $elements['map_marker_and_infowindow']['multivalue_split']['#states'] = [
        'visible' => [
          ':input[name="fields[' . $this->fieldDefinition
            ->getName() . '][settings_edit_form][settings][map_marker_and_infowindow][infowindow_field]"]' => $multivalue_fields_states,
        ],
      ];
    }
    else {
      $elements['map_marker_and_infowindow']['multivalue_split']['#description'] = $this
        ->t('If checked, each field value will be split into each matching infowindow /geofield , following the same progressive order<br>(The Multiple Field settings from the View Display will be used otherwise)');
      $elements['map_marker_and_infowindow']['multivalue_split']['#states'] = [
        'visible' => [
          ':input[name="style_options[map_marker_and_infowindow][infowindow_field]"]' => $multivalue_fields_states,
        ],
      ];
    }
    if (isset($this->fieldDefinition)) {

      // Get the human readable labels for the entity view modes.
      $view_mode_options = [];
      foreach ($this->entityDisplayRepository
        ->getViewModes($form['#entity_type']) as $key => $view_mode) {
        $view_mode_options[$key] = $view_mode['label'];
      }

      // The View Mode drop-down is visible conditional on "#rendered_entity"
      // being selected in the Description drop-down above.
      $elements['map_marker_and_infowindow']['view_mode'] = [
        '#type' => 'select',
        '#title' => $this
          ->t('View mode'),
        '#description' => $this
          ->t('View mode the entity will be displayed in the Infowindow.'),
        '#options' => $view_mode_options,
        '#default_value' => !empty($settings['map_marker_and_infowindow']['view_mode']) ? $settings['map_marker_and_infowindow']['view_mode'] : NULL,
        '#states' => [
          'visible' => [
            ':input[name$="[settings][map_marker_and_infowindow][infowindow_field]"]' => [
              'value' => '#rendered_entity',
            ],
          ],
        ],
      ];
    }
    if (isset($this->fieldDefinition)) {
      $elements['map_marker_and_infowindow']['force_open'] = [
        '#type' => 'checkbox',
        '#title' => $this
          ->t('Open Infowindow on Load'),
        '#description' => $this
          ->t('If checked the Infowindow will automatically open on page load.<br><b>Note:</b> in case of multivalue Geofield, the Infowindow will be opened (and the Map centered) on the first item.'),
        '#default_value' => !empty($settings['map_marker_and_infowindow']['force_open']) ? $settings['map_marker_and_infowindow']['force_open'] : 0,
        '#return_value' => 1,
      ];
    }
  }

  /**
   * Set Map Additional Options Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapAdditionalOptionsElement(array $settings, array &$elements) {
    $elements['map_additional_options'] = [
      '#type' => 'textarea',
      '#rows' => 5,
      '#title' => $this
        ->t('Map Additional Options'),
      '#description' => $this
        ->t('<strong>These will override the above settings</strong><br>An object literal of additional map options, that comply with the Google Maps JavaScript API.<br>The syntax should respect the javascript object notation (json) format.<br>As suggested in the field placeholder, always use double quotes (") both for the indexes and the string values.<br>It is even possible to input Map Control Positions. For this use the numeric values of the google.maps.ControlPosition, otherwise the option will be passed as incomprehensible string to Google Maps API.'),
      '#default_value' => $settings['map_additional_options'],
      '#placeholder' => '{"disableDoubleClickZoom": "cooperative",
"gestureHandling": "none",
"streetViewControlOptions": {"position": 5}
}',
      '#element_validate' => [
        [
          get_class($this),
          'jsonValidate',
        ],
      ],
    ];
  }

  /**
   * Set Overlapping Marker Spiderfier Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $default_settings
   *   The default settings array.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapOmsElement(array $settings, array $default_settings, array &$elements) {
    $elements['map_oms'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Overlapping Markers'),
      '#description' => $this
        ->t('<b>Note: </b>To make this working in conjunction with the Markercluster Option (see below) a "maxZoom" property should be set in the Marker Cluster Additional Options.'),
      '#description_display' => 'before',
    ];
    $elements['map_oms']['map_oms_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Spiderfy overlapping markers'),
      '#description' => $this
        ->t('Use the standard setup of the @overlapping_marker_spiderfier to manage Overlapping Markers located in the exact same position.', [
        '@overlapping_marker_spiderfier' => $this->link
          ->generate(t('Overlapping Marker Spiderfier Library (for Google Maps)'), Url::fromUri('https://github.com/jawj/OverlappingMarkerSpiderfier#overlapping-marker-spiderfier-for-google-maps-api-v3', [
          'absolute' => TRUE,
          'attributes' => [
            'target' => 'blank',
          ],
        ])),
      ]),
      '#default_value' => isset($settings['map_oms']['map_oms_control']) ? $settings['map_oms']['map_oms_control'] : $default_settings['map_oms']['map_oms_control'],
      '#return_value' => 1,
    ];
    $elements['map_oms']['map_oms_options'] = [
      '#type' => 'textarea',
      '#rows' => 2,
      '#title' => $this
        ->t('Markers Spiderfy Options'),
      '#description' => $this
        ->t('An object literal of Spiderfy options, that comply with the Overlapping Marker Spiderfier Library (see link above).<br>The syntax should respect the javascript object notation (json) format.<br>Always use double quotes (") both for the indexes and the string values.<br><b>Note: </b>This first three default options are the library ones suggested to save memory and CPU (in the simplest/standard implementation).'),
      '#default_value' => isset($settings['map_oms']['map_oms_options']) ? $settings['map_oms']['map_oms_options'] : $default_settings['map_oms']['map_oms_options'],
      '#placeholder' => '{"markersWontMove": "true", "markersWontHide": "true", "basicFormatEvents": "true", "nearbyDistance": 3}',
      '#element_validate' => [
        [
          get_class($this),
          'jsonValidate',
        ],
      ],
    ];
    if (isset($this->fieldDefinition)) {
      $elements['map_oms']['map_oms_options']['#states'] = [
        'visible' => [
          ':input[name="fields[' . $this->fieldDefinition
            ->getName() . '][settings_edit_form][settings][map_oms][map_oms_control]"]' => [
            'checked' => TRUE,
          ],
        ],
      ];
    }
    else {
      $elements['map_oms']['map_oms_options']['#states'] = [
        'visible' => [
          ':input[name="style_options[map_oms][map_oms_control]"]' => [
            'checked' => TRUE,
          ],
        ],
      ];
    }
  }

  /**
   * Set Custom Map Style Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setCustomStyleMapElement(array $settings, array &$elements) {
    $elements['custom_style_map'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Custom Styled Map'),
    ];
    $elements['custom_style_map']['custom_style_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Create a @custom_google_map_style_link.', [
        '@custom_google_map_style_link' => $this->link
          ->generate($this
          ->t('Custom Google Map Style'), Url::fromUri('https://developers.google.com/maps/documentation/javascript/examples/maptype-styled-simple', [
          'absolute' => TRUE,
          'attributes' => [
            'target' => 'blank',
          ],
        ])),
      ]),
      '#description' => $this
        ->t('This option allows to create a new map type, which the user can select from the map type control. The map type includes custom styles.'),
      '#default_value' => $settings['custom_style_map']['custom_style_control'],
      '#return_value' => 1,
    ];
    $elements['custom_style_map']['custom_style_name'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Custom Map Style Name'),
      '#description' => $this
        ->t('Input the Name of the Custom Map Style you want to create.'),
      '#default_value' => $settings['custom_style_map']['custom_style_name'],
      '#placeholder' => $this
        ->t('My Custom Map Style'),
      '#element_validate' => [
        [
          get_class($this),
          'customMapStyleValidate',
        ],
      ],
    ];
    $elements['custom_style_map']['custom_style_options'] = [
      '#type' => 'textarea',
      '#rows' => 5,
      '#title' => $this
        ->t('Custom Map Style Options'),
      '#description' => $this
        ->t('An object literal of map style options, that comply with the Google Maps JavaScript API.<br>The syntax should respect the javascript object notation (json) format.<br>As suggested in the field placeholder, always use double quotes (") both for the indexes and the string values.<br>(As a useful reference consider using @snappy_maps).', [
        '@snappy_maps' => $this->link
          ->generate($this
          ->t('Snappy Maps'), Url::fromUri('https://snazzymaps.com', [
          'absolute' => TRUE,
          'attributes' => [
            'target' => 'blank',
          ],
        ])),
      ]),
      '#default_value' => $settings['custom_style_map']['custom_style_options'],
      '#placeholder' => $this->customMapStylePlaceholder,
      '#element_validate' => [
        [
          get_class($this),
          'jsonValidate',
        ],
        [
          get_class($this),
          'customMapStyleValidate',
        ],
      ],
    ];
    $elements['custom_style_map']['custom_style_default'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Force the Custom Map Style as Default'),
      '#description' => $this
        ->t('The Custom Map Style will be the Default starting one.'),
      '#default_value' => $settings['custom_style_map']['custom_style_default'],
      '#return_value' => 1,
    ];
    if (isset($this->fieldDefinition)) {
      $custom_style_map_control_selector = ':input[name="fields[' . $this->fieldDefinition
        ->getName() . '][settings_edit_form][settings][custom_style_map][custom_style_control]"]';
    }
    else {
      $custom_style_map_control_selector = ':input[name="style_options[custom_style_map][custom_style_control]"]';
    }
    $elements['custom_style_map']['custom_style_name']['#states'] = [
      'visible' => [
        $custom_style_map_control_selector => [
          'checked' => TRUE,
        ],
      ],
      'required' => [
        $custom_style_map_control_selector => [
          'checked' => TRUE,
        ],
      ],
    ];
    $elements['custom_style_map']['custom_style_options']['#states'] = [
      'visible' => [
        $custom_style_map_control_selector => [
          'checked' => TRUE,
        ],
      ],
    ];
    $elements['custom_style_map']['custom_style_default']['#states'] = [
      'visible' => [
        $custom_style_map_control_selector => [
          'checked' => TRUE,
        ],
      ],
    ];
  }

  /**
   * Set Map Marker Cluster Element.
   *
   * @param array $settings
   *   The Form Settings.
   * @param array $elements
   *   The Form element to alter.
   */
  private function setMapMarkerclusterElement(array $settings, array &$elements) {
    $elements['map_markercluster'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Marker Clustering'),
    ];
    $elements['map_markercluster']['markup'] = [
      '#markup' => $this
        ->t('Enable the functionality of the @markeclusterer_api_link.', [
        '@markeclusterer_api_link' => $this->link
          ->generate($this
          ->t('Marker Clusterer Google Maps JavaScript Library'), Url::fromUri('https://github.com/googlemaps/js-marker-clusterer', [
          'absolute' => TRUE,
          'attributes' => [
            'target' => 'blank',
          ],
        ])),
      ]),
    ];
    $elements['map_markercluster']['markercluster_control'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Enable Marker Clustering'),
      '#default_value' => $settings['map_markercluster']['markercluster_control'],
      '#return_value' => 1,
    ];
    $elements['map_markercluster']['markercluster_additional_options'] = [
      '#type' => 'textarea',
      '#rows' => 4,
      '#title' => $this
        ->t('Marker Cluster Additional Options'),
      '#description' => $this
        ->t('An object literal of additional marker cluster options, that comply with the Marker Clusterer Google Maps JavaScript Library.<br>The syntax should respect the javascript object notation (json) format.<br>As suggested in the field placeholder, always use double quotes (") both for the indexes and the string values.'),
      '#default_value' => $settings['map_markercluster']['markercluster_additional_options'],
      '#placeholder' => '{"maxZoom": 12, "gridSize": 25, "imagePath": "https://developers.google.com/maps/documentation/javascript/examples/full/images/beachflag.png"}',
      '#element_validate' => [
        [
          get_class($this),
          'jsonValidate',
        ],
      ],
    ];
    $elements['map_markercluster']['markercluster_warning'] = [
      '#type' => 'container',
      'warning' => [
        '#type' => 'html_tag',
        '#tag' => 'span',
        '#value' => $this
          ->t('WARNING:') . " ",
        '#attributes' => [
          'class' => [
            'geofield-map-warning',
          ],
        ],
      ],
      'warning_text' => [
        '#type' => 'html_tag',
        '#tag' => 'span',
        '#value' => $this
          ->t('Markers Spiderfy is Active ! | If not, a "maxZoom" property should be set in the Marker Cluster Additional Options to be able to output the Spederfy effect.'),
      ],
    ];
    if (isset($this->fieldDefinition)) {
      $elements['map_markercluster']['markercluster_additional_options']['#states'] = [
        'visible' => [
          ':input[name="fields[' . $this->fieldDefinition
            ->getName() . '][settings_edit_form][settings][map_markercluster][markercluster_control]"]' => [
            'checked' => TRUE,
          ],
        ],
      ];
      $elements['map_markercluster']['markercluster_warning']['#states'] = [
        'visible' => [
          ':input[name="fields[' . $this->fieldDefinition
            ->getName() . '][settings_edit_form][settings][map_oms][map_oms_control]"]' => [
            'checked' => TRUE,
          ],
        ],
        'invisible' => [
          ':input[name="fields[' . $this->fieldDefinition
            ->getName() . '][settings_edit_form][settings][map_markercluster][markercluster_control]"]' => [
            'checked' => FALSE,
          ],
        ],
      ];
    }
    else {
      $elements['map_markercluster']['markercluster_additional_options']['#states'] = [
        'visible' => [
          ':input[name="style_options[map_markercluster][markercluster_control]"]' => [
            'checked' => TRUE,
          ],
        ],
      ];
      $elements['map_markercluster']['markercluster_warning']['#states'] = [
        'visible' => [
          ':input[name="style_options[map_oms][map_oms_control]"]' => [
            'checked' => TRUE,
          ],
        ],
        'invisible' => [
          ':input[name="style_options[map_markercluster][markercluster_control]"]' => [
            'checked' => FALSE,
          ],
        ],
      ];
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
GeofieldMapFieldTrait::$customMapStylePlaceholder protected property
GeofieldMapFieldTrait::$gMapTypesOptions protected property Google Map Types Options.
GeofieldMapFieldTrait::$infowindowFieldTypesOptions protected property Google Map Types Options.
GeofieldMapFieldTrait::customMapStyleValidate public static function Form element validation handler for a Custom Map Style Name Required.
GeofieldMapFieldTrait::generateGmapSettingsForm public function Generate the Google Map Settings Form.
GeofieldMapFieldTrait::getDefaultSettings public static function Get the Default Settings.
GeofieldMapFieldTrait::getGeoJsonData protected function Transform Geofield data into Geojson features.
GeofieldMapFieldTrait::getGmapApiKey private function Get the GMap Api Key from the geofield_map settings/configuration.
GeofieldMapFieldTrait::jsonValidate public static function Form element json format validation handler.
GeofieldMapFieldTrait::maxZoomLevelValidate public static function Form element validation handler for the Map Max Zoom level.
GeofieldMapFieldTrait::preProcessMapSettings protected function Pre Process the MapSettings.
GeofieldMapFieldTrait::setCustomStyleMapElement private function Set Custom Map Style Element.
GeofieldMapFieldTrait::setMapAdditionalOptionsElement private function Set Map Additional Options Element.
GeofieldMapFieldTrait::setMapCenterElement private function Set Map Center Element.
GeofieldMapFieldTrait::setMapControlsElement private function Set Map Control Element.
GeofieldMapFieldTrait::setMapDimensionsElement private function Set Map Dimension Element.
GeofieldMapFieldTrait::setMapEmptyElement private function Set Map Empty Options Element.
GeofieldMapFieldTrait::setMapGoogleApiKeyElement private function Set Map Google Api Key Element.
GeofieldMapFieldTrait::setMapMarkerAndInfowindowElement private function Set Map Marker and Infowindow Element.
GeofieldMapFieldTrait::setMapMarkerclusterElement private function Set Map Marker Cluster Element.
GeofieldMapFieldTrait::setMapOmsElement private function Set Overlapping Marker Spiderfier Element.
GeofieldMapFieldTrait::setMapZoomAndPanElement private function Set Map Zoom and Pan Element.
GeofieldMapFieldTrait::urlValidate public static function Form element url format validation handler.
GeofieldMapFieldTrait::zoomLevelValidate public static function Form element validation handler for a Map Zoom level.