ip_geoloc-2.0.0-alpha0/src/Form/SetLocationForm.php

src/Form/SetLocationForm.php
<?php

namespace Drupal\ip_geoloc\Form;

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\ip_geoloc\Services\IpGeoLocSession;
use Drupal\ip_geoloc\Services\IpGeoLocAPI;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Peding doc.
 */
class SetLocationForm extends FormBase {

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The IP Geolocation API service.
   *
   * @var \Drupal\ip_geoloc\Services\IpGeoLocAPI
   */
  protected $api;

  /**
   * The IP Geolocation Session service.
   *
   * @var \Drupal\ip_geoloc\Services\IpGeoLocSession
   */
  protected $session;

  /**
   * The Module Handler service.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * The Request Stack service.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The Entity Type Manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The Entity Field Manager service.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * {@inheritdoc}
   */
  public function __construct(MessengerInterface $messenger, ConfigFactoryInterface $config_factory, IpGeoLocAPI $api, IpGeoLocSession $session, ModuleHandlerInterface $module_handler, RequestStack $request_stack, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
    parent::__construct($config_factory);
    $this->messenger = $messenger;
    $this->api = $api;
    $this->session = $session;
    $this->moduleHandler = $module_handler;
    $this->requestStack = $request_stack;
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
        $container->get('messenger'),
        $container->get('config.factory'),
        $container->get('ip_geoloc.api'),
        $container->get('ip_geoloc.session'),
        $container->get('module_handler'),
        $container->get('request_stack'),
        $container->get('entity_type.manager'),
        $container->get('entity_field.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'ip_geoloc_set_location_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Migration comment:  Part of ip_geoloc_set_location_form definition.
    $ip_geoloc_config = $this->config('ip_geoloc.settings');

    $has_find_visitor = $ip_geoloc_config->get('ip_geoloc_visitor_find') ? $ip_geoloc_config->get('ip_geoloc_visitor_find') : TRUE;
    $is_address_editable = $ip_geoloc_config->get('ip_geoloc_visitor_address_editable') ? $ip_geoloc_config->get('ip_geoloc_visitor_address_editable') : TRUE;
    $geo_vocabulary_id = $ip_geoloc_config->get('ip_geoloc_geo_vocabulary_id') ? $ip_geoloc_config->get('ip_geoloc_geo_vocabulary_id') : 0;

    if (!$has_find_visitor && !$is_address_editable && !$geo_vocabulary_id) {
      $this->messenger->addError($this->t('You should select at least one of the three widgets available for the "Set my location" block.'));
      return $form;
    }

    $location = $this->api->getVisitorLocation();

    $form['#attributes']['id'] = $ajax_wrapper_id = Html::getUniqueId('set-location-form');

    if ($has_find_visitor) {
      $this->setMyLocationAddFindMe($form, $ajax_wrapper_id);
    }

    $options = $this->setMyLocationAddSelector($form, $location, $is_address_editable, $geo_vocabulary_id);

    $is_reverse_geocode = $has_find_visitor && $ip_geoloc_config->get('ip_geoloc_visitor_reverse_geocode') ? $ip_geoloc_config->get('ip_geoloc_visitor_reverse_geocode') : TRUE;

    if ($is_reverse_geocode || $is_address_editable) {
      $this->setMyLocationAddAddress($form, $location);
    }

    if ($geo_vocabulary_id) {
      $this->setMyLocationAddRegion($form, $location, $geo_vocabulary_id);
    }

    $this->setMyLocationAddLogic($form, $location, $options, $is_address_editable, $geo_vocabulary_id);

    if ($is_address_editable || $geo_vocabulary_id) {
      $form['submit_address'] = [
        '#type' => 'submit',
        '#value' => t('Go'),
        '#submit' => ['_ip_geoloc_process_go_to_submit'],
        '#weight' => 15,
      ];
    }

    $form['#attributes']['class'][] = 'ip-geoloc-address';
    $form['#attached']['library'][] = 'ip_geoloc/ip_geoloc.client';
    return $form;

  }

  /*
 * The value of the 'fixed_address' selector is stored on the location, as
 * stored on the session. Its value is coded as follows:
 *   0: "Find me" button pressed
 *   1: "Move to" selected and "Go" pressed
 *   2: "Region" selected and "Go" pressed
 */
function setMyLocationAddLogic(&$form, $location, $options, $is_address_editable, $geo_vocabulary_id) {

  $fixed_address = empty($location['fixed_address']) ? 0 : (int)$location['fixed_address'];

  // Check if we have a "Region/Move to" drop-down ...
  if (isset($form['fixed_address'])) {
    // Default to "Move to", unless we do not have a location at all, or when
    // "Region" was selected and "Go" pressed.
    $selected = '1';
    if (isset($options['2']) && !isset($location['fixed_address']) || $fixed_address == 2) {
      $selected = '2';
    }
    $form['fixed_address']['#default_value'] = $selected;
  }

  // Disable the address box when it isn't editable.
  $form['street_address']['#disabled'] = !$is_address_editable;

  // Special logic for when there's a Region selector
  if ($geo_vocabulary_id) {

    // If "Move to" is NOT there, remove Address box when Go was pressed.
    if (!isset($options['1']) && $fixed_address == 2) {
      unset($form['street_address']);
    }
    elseif (count($options) > 1) {
      // If 2 or more options, then hide Address box when Region pressed.
      $form['street_address']['#states'] = array(
        'invisible' => array('select[name="fixed_address"]' => array('value' => '2')),
      );
    }
  }
}

  function setMyLocationAddAddress(&$form, $location) {
    $ip_geoloc_config = $this->config('ip_geoloc.settings');
    $textarea = $ip_geoloc_config->get('ip_geoloc_address_element', 2);
    $default_address = Html::escape($ip_geoloc_config->get('ip_geoloc_visitor_address_default', ''));
    $form['street_address'] = array(
      '#type' => $textarea ? 'textarea' : 'textfield',
      '#rows' => $textarea,
      '#default_value' => empty($location['formatted_address']) ? $default_address : $location['formatted_address'],
      '#weight' => 10,
    );
  }

  function setMyLocationAddSelector(&$form, &$location, $is_address_editable, $geo_vocabulary_id) {
    $ip_geoloc_config = $this->config('ip_geoloc.settings');
    $options = array();
    $editable_address_label = $ip_geoloc_config->get('ip_geoloc_visitor_address_label', '');
    $editable_region_label = $ip_geoloc_config->get('ip_geoloc_visitor_region_label', '');
  
    if ($is_address_editable && $editable_address_label != '<none>') {
      $options['1'] = $editable_address_label ? Xss::filterAdmin($editable_address_label) : IP_GEOLOC_VISITOR_DEFAULT_ADDRESS_LABEL;
    }
    if ($geo_vocabulary_id && $editable_region_label != '<none>') {
      $options['2'] = $editable_region_label ? Xss::filterAdmin($editable_region_label) : IP_GEOLOC_VISITOR_DEFAULT_REGION_LABEL;
    }
    if (!empty($options)) {
      $form['fixed_address'] = array(
        '#type' => count($options) <= 1 ? 'markup' : 'select',
        '#options' => $options,
        '#default_value' => isset($options['2']) ? '2' : '1',
        '#markup' => isset($options['1']) ? $options['1'] : $options['2'],
        '#weight' => 5,
      );
    }
    return $options;
  }


  function setMyLocationAddFindMe(&$form, $ajax_wrapper_id) {
    $ip_geoloc_config = $this->config('ip_geoloc.settings');
    $find_visitor_label = $ip_geoloc_config->get('ip_geoloc_visitor_find_label', '');
    $find_visitor_label = empty($find_visitor_label) ? IP_GEOLOC_VISITOR_DEFAULT_FIND_LABEL : Xss::filterAdmin($find_visitor_label);
  
    // See _ip_geoloc_process_find_me_ajax() for why this is done here.
    if ($ip_geoloc_config->get('ip_geoloc_visitor_reverse_geocode')) {
      $form['#attached']['js'][] = IP_GEOLOC_GOOGLE_MAPS;
    }
    $form['find'] = array(
      // Use 'submit' to go with '#submit'. For #ajax 'button' may be used too.
      '#type' => 'submit',
      '#value' => $find_visitor_label,
      '#submit' => array('_ip_geoloc_process_find_me_submit'),
      '#ajax' => array(
        'callback' => '_ip_geoloc_process_find_me_ajax',
        'wrapper' => $ajax_wrapper_id,
        'progress' => FALSE,
      ),
      '#weight' => $ip_geoloc_config->get('ip_geoloc_visitor_find_position', 0),
    );
    $throbber_text = $ip_geoloc_config->get('ip_geoloc_throbber_text', '');
    if (empty($throbber_text)) {
      $throbber_text = IP_GEOLOC_THROBBER_DEFAULT_TEXT;
    }
    if ($throbber_text != '<none>') {
      $form['find']['#ajax']['progress'] = array(
        'type' => 'throbber',
        'message' => Xss::filterAdmin($throbber_text),
      );
    }
  }

  function setMyLocationAddRegion(&$form, $location, $geo_vocabulary_id) {
    $ip_geoloc_config = $this->config('ip_geoloc.settings');
    $regions = array(0 => '--' . t('none') . '--');
    foreach ($this->entityTypeManager->getStorage('taxonomy_term')->loadTree($geo_vocabulary_id) as $term) {
      $regions[$term->tid] = str_repeat('-', $term->depth) . $term->name;
      if (isset($location['region']) && $location['region'] == $term->tid) {
        $current_region_name = $term->name;
      }
    }
    if ($ip_geoloc_config->get('ip_geoloc_region_autocomplete')) {
      // Use an autocomplete textfield, instead of a drop-down selector.
      $form['region'] = array(
        '#type' => 'textfield',
        '#size' => 29,
        '#default_value' => isset($current_region_name) ? $current_region_name : '',
        '#description' => t('Type the first letters of a region.'),
        // Refer to hook_menu().
        '#autocomplete_path' => 'ip_geoloc/region_autocomplete',
        '#executes_submit_callback' => TRUE,
        '#weight' => 10,
      );
    }
    else {
      $form['region'] = array(
        '#type' => 'select',
        '#options' => $regions,
        '#default_value' => isset($location['region']) ? $location['region'] : 0,
        '#weight' => 10,
      );
    }
    $form['region']['#states'] = array(
      'visible' => array('select[name="fixed_address"]' => array('value' => '2')),
    );
  }

  /**
   * Returns the supplied string into an array with various address components.
   *
   * @param string $partial_address_or_landmark
   * @return array, a location holding, latitude, longitude and address fields
   */
  function setLocationFromAddress($partial_address_or_landmark) {

    if (empty($partial_address_or_landmark)) {
      $location = array(
        'provider' => 'user',
        'ip_address' => $this->requestStack->getCurrentRequest()->getClientIp(),
      );
    }
    else {
      if ($this->moduleHandler->moduleExists('geocoder')) {
        // Use Google server-side API to retrieve lat/long from entered text, as
        // well as all components of the full address.

        $geocoder = \Drupal::service('geocoder');
        $point =  $geocoder->geocode($partial_address_or_landmark, ['google']);
      }
      else {
        $this->messenger->addMessage(
          t('<a target="project_page" href="@geocoder">Geocoder</a> module must be enabled to geocode an address.', [
          '@geocoder' => Url::fromUri('http://drupal.org/project/geocoder')->toString()]),
          'warning');
      }
      if (empty($point)) {
        $this->messenger->addMessage(t('The address %address could not be geocoded to a location.', array(
          '%address' => $partial_address_or_landmark)), 'warning');
      }
      else {
        $location = array(
          'provider' => 'user+google',
          'is_updated' => TRUE,
          'ip_address' => $this->requestStack->getCurrentRequest()->getClientIp(),
          'latitude' => $point->coords[1],
          'longitude' => $point->coords[0],
          'formatted_address' => $point->data['geocoder_formatted_address'],
          'accuracy' => $point->data['geocoder_accuracy'],
        );
        // Flatten the point object into a straight location array.
        foreach ($point->data['geocoder_address_components'] as $component) {
          if (!empty($component->long_name)) {
            $type = $component->types[0];
            $location[$type] = $component->long_name;
            if ($type == 'country' && !empty($component->short_name)) {
              $location['country_code'] = $component->short_name;
            }
          }
        }
      }
    }
    $location['fixed_address'] = 1;
    return $location;
  }

  function setLocationFromRegion($region_name_or_tid) {
    $ip_geoloc_config = $this->config('ip_geoloc.settings');
    if (!is_numeric($region_name_or_tid)) {
      $geo_vocabulary_id = $ip_geoloc_config->get('ip_geoloc_geo_vocabulary_id', 0);
      foreach ($this->entityTypeManager->getStorage('taxonomy_term')->loadTree($geo_vocabulary_id) as $term) {
        if (strcasecmp($term->name, $region_name_or_tid) === 0) {
          $region_name_or_tid = $term->tid;
          break;
        }
      }
    }
    $parent = $ip_geoloc_config->get('ip_geoloc_region_parent', 0);
    $location = $this->getLocationFromTerm($region_name_or_tid, $parent);
    $location['fixed_address'] = 2;
    return $location;
  }

  /**
 * Returns the location object belonging to supplied region taxonomy term id.
 *
 * @param int $tid
 *   Taxonomy term identifier
 * @param int $return_parent
 *   To return location of the parent (1) or grand-parent (2) rather than the
 *   supplied region term.
 *
 * @return array, location info
 */
function getLocationFromTerm($tid, $parent = 0) {
  $ip_geoloc_config = $this->config('ip_geoloc.settings');
  $term = $this->entityTypeManager->getStorage('taxonomy_term')->load($tid);
  $parents = $term->getParents();
  if (empty($parents)) {
    return array('provider' => 'taxonomy', 'ip_address' => $this->requestStack->getCurrentRequest()->getClientIp());
  }
  $term = $parents[min($parent, count($parents) - 1)];

  // Get lat,lng from the Geofield on this term
  $geo_vocabulary_id = $ip_geoloc_config->get('ip_geoloc_geo_vocabulary_id', 0);
  $vocabulary = $this->entityTypeManager->getStorage('taxonomy_vocabulary')->load($geo_vocabulary_id);

  $fields_definition = $this->entityFieldManager->getFieldDefinitions('taxonomy_term', $vocabulary->machine_name);
  foreach ($fields_definition as $field_name => $field_instance) {
    $field = $field_instance->getType();
    if ($field['type'] == 'geofield') {
      $value = reset($term->{$field_name});
      $value = is_array($value) ? reset($value) : array();
      if (empty($value['lat'])) {
        $this->messenger->addMessage(t('The latitude and longitude of the term %name are not known.', array('%name' => $field_name)), 'warning');
        $value = array('lat' => NULL, 'lon' => NULL);
      }
      return array(
        'provider' => 'taxonomy',
        'is_updated' => TRUE,
        'ip_address' => $this->requestStack->getCurrentRequest()->getClientIp(),
        'region' => $term->tid,
        'latitude' => $value['lat'],
        'longitude' => $value['lon'],
      //'formatted_address' => $term->name,
      );
    }
  }
}


  /**
   * {@inheritdoc}
   */
  public function submitForm(array $form, FormStateInterface $form_state) {
    // Migration comment:  Part of _ip_geoloc_process_go_to_submit for submiting ip_geoloc_set_location_form.
    // Clear any pending location retrieval process that may be in process.
    $this->session->setSessionValue('last_position_check', time());
    $this->session->setSessionValue('position_pending_since', NULL);

    $geo_vocabulary_id = \Drupal::state()->get('ip_geoloc_geo_vocabulary_id', 0);

    if ($form_state->isValueEmpty('fixed_address')) {
      // Nothing slected. As 'Go' was pressed we need to choose 1 or 2.
      $form_state->setValue('fixed_address', $geo_vocabulary_id ? '2' : '1');
    }

    if ($form_state->getValue('fixed_address') == '1') {
      // Using new 'input' rather than current 'values'.
      $input = $form_state->get('input');
      if(!empty($input['street_address'])) {
        $entered_address = Html::escape($input['street_address']);
      }else {
        $entered_address = NULL;
      }
      $location = $this->setLocationFromAddress($entered_address);
    }
    elseif ($geo_vocabulary_id) {
      // "Region" selected.
      $location = $this->setLocationFromRegion($form_state->getValue('region'));
    }
    // Wipe old location before setting the new one (to avoid merging).
    $this->session->setSessionValue('location', NULL);
    $this->session->setSessionValue('location', $location);

    $redirect = \Drupal::state()->get('ip_geoloc_address_redirect');
    if (!empty($redirect)) {
      $form_state->set('redirect',$redirect);
    }
    // No need to remember the form state. It's all kept on the session.
    // Also, if set to TRUE, content is rendered before new location is set
    // and Region selector will be one step behind.
    $form_state->setRebuild();
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc