openlayers-8.x-4.x-dev/src/Form/OpenlayersMapFormBase.php

src/Form/OpenlayersMapFormBase.php
<?php

namespace Drupal\openlayers\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

use Drupal\Core\Link;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Url;

use Drupal\openlayers\OpenlayersPluginManager;
//use Drupal\openlayers\LayerPluginManager;
//use Drupal\openlayers\StylePluginManager;
//use Drupal\openlayers\ControlPluginManager;
//use Drupal\openlayers\InteractionPluginManager;

use Drupal\openlayers\OpenlayersPluginCollection;
use Drupal\openlayers\OpenlayersConfigurablePluginInterface;

/**
 * Base form for Openlayers Maps add and edit configuration forms.
 */
class OpenlayersMapFormBase extends EntityForm {
  
  /**
   * The entity being used by this form.
   *
   * @var \Drupal\image\ImageStyleInterface
   */
  protected $entity;

  /**
   * The image style entity storage.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $entityStorage;

  /**
   * The image effect manager service.
   *
   * @var \Drupal\image\ImageEffectManager
   */
  protected $openlayersPluginManager;
//  protected $layerPluginManager;
//  protected $stylePluginManager;
//  protected $controlPluginManager;
//  protected $interactionPluginManager;
  
  /**
   * Constructs a base class for image style add and edit forms.
   *
   * @param \Drupal\Core\Entity\EntityStorageInterface $image_style_storage
   *   The image style entity storage.
   */
  public function __construct(
      EntityStorageInterface $entity_storage,
      OpenlayersPluginManager $openlayers_plugin_manager,
//      LayerPluginManager $layer_plugin_manager,
//      StylePluginManager $style_plugin_manager, 
//      ControlPluginManager $control_plugin_manager, 
//      InteractionPluginManager $interaction_plugin_manager
  ) {
    $this->entityStorage = $entity_storage;
    $this->openlayersPluginManager = $openlayers_plugin_manager;
//    $this->layerPluginManager = $layer_plugin_manager;
//    $this->stylePluginManager = $style_plugin_manager;
//    $this->controlPluginManager = $control_plugin_manager;
//    $this->interactionPluginManager = $interaction_plugin_manager;
  }
  
  public static function create(ContainerInterface $container) {
    $form = new static(
      $container->get('entity_type.manager')->getStorage('openlayers_map'),
      $container->get('plugin.manager.openlayers'),
//      $container->get('plugin.manager.openlayers.layer'),
//      $container->get('plugin.manager.openlayers.style'),
//      $container->get('plugin.manager.openlayers.control'),
//      $container->get('plugin.manager.openlayers.interaction')
    );
    $form->setMessenger($container->get('messenger'));
    return $form;
  }

  public function buildForm(array $form, FormStateInterface $form_state) {

    // Get anything we need from the base class.
    $form = parent::buildForm($form, $form_state);

    $user_input = $form_state->getUserInput();
    
    $form['#title'] = $this->t('Edit %name map', ['%name' => $this->entity->label()]);
    $form['#tree'] = TRUE;
    $form['#attached']['library'][] = 'openlayers/admin';

    // Drupal provides the entity to us as a class variable. If this is an
    // existing entity, it will be populated with existing values as class
    // variables. If this is a new entity, it will be a new object with the
    // class of our entity. Drupal knows which class to call from the
    // annotation on our Control class.

    $openlayers_map = $this->entity;

    // Build the form.
    $form['label'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Label'),
      '#maxlength' => 255,
      '#default_value' => $openlayers_map->label(),
      '#required' => TRUE,
    ];
    $form['id'] = [
      '#type' => 'machine_name',
      '#title' => $this->t('Machine name'),
      '#default_value' => $openlayers_map->id(),
      '#machine_name' => [
        'exists' => [$this, 'exists'],
        'replace_pattern' => '([^a-z0-9_]+)|(^custom$)',
        'error' => 'The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".',
      ],
      '#disabled' => !$openlayers_map->isNew(),
    ];

    $form['service'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Factory Service'),
      '#default_value' => 'openlayers.Map:OLMap',
      '#disabled' => TRUE,
    ];

    $form['pluginId'] = [
      '#type' => 'value',
      '#value' => 'OLMap',
    ];

    //  Start of layers / styles / controls subforms

    foreach (['layer', 'control', 'style', 'interaction', 'component'] as $type) {
      $types = $type . 's';
    
      // Build the list of existing objects for this map.
      $form[$types] = [
        '#type' => 'table',
        '#header' => [
          $this->t(ucfirst($types)),
          $this->t('Weight'),
          $this->t('Operations'),
        ],
        '#tabledrag' => [
          [
            'action' => 'order',
            'relationship' => 'sibling',
            'group' => 'ol-' . $type . '-order-weight',
          ],
        ],
        '#attributes' => [
          'id' => 'ol-map-' . $types,
        ],
        '#empty' => t('There are currently no ' . $types . ' in this map. Add one by selecting an option below.'),
        '#weight' => 5,
      ];
     
      // Build the list of new objects that can be added to the map (excluding those that are already attached to the map?).
      $all_objects = $this->entity->getAllObjects($type);
      $map_objects = $this->entity->getObjects($type);

      foreach ($map_objects->getConfigurations() as $key => $object_info) {
        $object = \Drupal::entityTypeManager()
          ->getStorage('openlayers_' . $type)
          ->load($object_info['id'])
        ;

        if ($object !== null) {
          $label = $object->label();
          $id = $object->id();
          $is_configurable = $object->is_configurable;
        } else {
          $label = 'Unknown';
          $id = 'Unknown';
          $is_configurable = false;
        }

        $form[$types][$key]['#attributes']['class'][] = 'draggable';

        $form[$types][$key][$type] = [
          '#tree' => FALSE,
          'data' => [
            'label' => [
              '#plain_text' => $label . ' (' . $id . ')',
            ],
          ],
        ];

        $form[$types][$key]['weight'] = [
          '#type' => 'weight',
          '#title' => $this->t('Weight for @title', ['@title' => 'xxxxxx']),
          '#title_display' => 'invisible',
          '#default_value' => isset($object_info['weight']) ? $object_info['weight'] : 0,
          '#attributes' => [
            'class' => ['ol-' . $type . '-order-weight'],
          ],
        ];

        $links = [];

        if ($is_configurable) {
          $links['edit'] = [
            'title' => $this->t('Edit'),          
            'url' => Url::fromRoute('openlayers.map.' . $type . '_edit_form', [
              'map' => $this->entity->id(),
              $type => $key,
            ]),
          ];
        }
        $links['delete'] = [
          'title' => $this->t('Delete'),
          'url' => Url::fromRoute('openlayers.map.' . $type . '_delete', [
              'map' => $this->entity->id(),
              $type => $key,
          ]),
        ];
        $form[$types][$key]['operations'] = [
          '#type' => 'operations',
          '#links' => $links,
        ];

        $form[$types][$key]['uuid'] = [
          '#type' => 'value',
          '#value' => $object_info['uuid'],
        ];

        $form[$types][$key]['id'] = [
          '#type' => 'value',
          '#value' => $object_info['id'],
        ];

        $form[$types][$key]['data'] = [
          '#type' => 'value',
          '#value' => isset($object_info['data']) ? $object_info['data'] : [],
        ];
      }

      // Build the new object addition form and add it to the object list.
      asort($all_objects);

      $form[$types]['new'] = [
        '#tree' => FALSE,
        '#weight' => isset($user_input['weight']) ? $user_input['weight'] : NULL,       //  TODO - ???
        '#attributes' => ['class' => ['draggable']],
      ];
      $form[$types]['new'][$type] = [
        'data' => [
          'new_' . $type => [
            '#type' => 'select',
            '#title' => $this->t($type),
            '#title_display' => 'invisible',
            '#options' => $all_objects,
            '#empty_option' => $this->t('Select a new ' . $type),
          ],
          [
            'add' => [
              '#type' => 'submit',
              '#value' => $this->t('Add ' . $type),
              '#name' => 'add_' . $type,
              '#validate' => ['::ObjectValidate'],
              '#submit' => ['::submitForm', '::ObjectSave'],
            ],
          ],
        ],
        '#prefix' => '<div class="map-' . $type . '-new">',
        '#suffix' => '</div>',
      ];

      $form[$types]['new']['weight'] = [
        '#type' => 'weight',
        '#title' => $this->t('Weight for new ' . $type),
        '#title_display' => 'invisible',
        '#default_value' => 0,
        '#attributes' => ['class' => ['ol-' . $type . '-order-weight']],
      ];
      $form[$types]['new']['operations'] = [
        'data' => [],
      ];
    }

    //  End of layers / styles / controls / interactions / components subforms

    //  Finally set the options for the Openlayers Map View.
    $form['map_view'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Map View'),    
      '#weight' => 50,
    ];

    $form['map_view']['center'] = [
      '#type' => 'fieldset',
      '#title' => $this->t('Center'),
    ];
    
    $form['map_view']['center']['lat'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Latitude'),
      '#size' => 20,
      '#default_value' => isset($openlayers_map->map_view['center']['lat']) ? (int)$openlayers_map->map_view['center']['lat'] : 0,
    ];

    $form['map_view']['center']['lon'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Longitude'),
      '#size' => 20,
      '#description' => $this->t('Latitude / longitude should be expressed in degrees.'),
      '#default_value' => isset($openlayers_map->map_view['center']['lon']) ? (int)$openlayers_map->map_view['center']['lon'] : 0,
    ];

    $zoom_options = [1 => '1', 2 => '2', 3 => '3', 4 => '4', 5 => '5', 6 => '6'];  //  TODO
    
    $form['map_view']['zoom'] = [
      '#type' => 'select',
      '#title' => $this->t('Zoom'),
      '#options' => $zoom_options,
      '#empty_option' => $this->t('Select an initial zoom'),
      '#default_value' => isset($openlayers_map->map_view['zoom']) ? $openlayers_map->map_view['zoom'] : 0,
    ];

    $projection_options = ['EPSG:3857' => 'EPSG:3857', 'bb' => 'BB', 'cc' => 'CC'];   //  TODO

    $form['map_view']['projection'] = [
      '#type' => 'select',
      '#title' => $this->t('Projection'),
      '#options' => $projection_options,
      '#empty_option' => $this->t('Select a projection'),
      '#default_value' => isset($openlayers_map->map_view['projection']) ? $openlayers_map->map_view['projection'] : 'EPSG:3857',
    ];

    $form['map_view']['rotation'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Rotation'),
      '#default_value' => isset($openlayers_map->map_view['rotation']) ? $openlayers_map->map_view['rotation'] : 0,
    ];

    $form['map_view']['force'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Force'),
      '#description' => $this->t('Forces the initial center / zoom, rather than let the map calculate this automatically based on the features.'),
      '#default_value' => isset($openlayers_map->map_view['force']) ? $openlayers_map->map_view['force'] : false,
    ];

    // Return the form.
    return $form;
  }

  /**
   * Checks for an existing openlayers_map.
   *
   * @param string|int $entity_id
   *   The entity ID.
   * @param array $element
   *   The form element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return bool
   *   TRUE if this format already exists, FALSE otherwise.
   */
  public function exists($entity_id, array $element, FormStateInterface $form_state) {
    // Use the query factory to build a new openlayers_map entity query.
    $query = $this->entityStorage->getQuery();

    // Query the entity ID to see if its in use.
    $result = $query->condition('id', $element['#field_prefix'] . $entity_id)
      ->execute();

    // We don't need to return the ID, only if it exists or not.
    return (bool) $result;
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::actions().
   *
   * To set the submit button text, we need to override actions().
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   An associative array containing the current state of the form.
   *
   * @return array
   *   An array of supported actions for the current entity form.
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    // Get the basic actins from the base class.
    $actions = parent::actions($form, $form_state);

    // Change the submit button text.
    $actions['submit']['#value'] = $this->t('Save');

    // Return the result.
    return $actions;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);

    // Add code here to validate your config entity's form elements.
    // Nothing to do here.
  }

  public function submit(array &$form, FormStateInterface $form_state) {
    parent::submit($form, $form_state);
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::save().
   *
   * Saves the entity. This is called after submit() has built the entity from
   * the form values. Do not override submit() as save() is the preferred
   * method for entity form controllers.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   An associative array containing the current state of the form.
   */
  public function save(array $form, FormStateInterface $form_state) {
    // EntityForm provides us with the entity we're working on.
    $openlayers_map = $this->getEntity();

    // Drupal already populated the form values in the entity object. Each
    // form field was saved as a public variable in the entity class. PHP
    // allows Drupal to do this even if the method is not defined ahead of
    // time.
    $status = $openlayers_map->save();

    // Grab the URL of the new entity. We'll use it in the message.
    $url = $openlayers_map->toUrl();

    // Create an edit link.
    $edit_link = Link::fromTextAndUrl($this->t('Edit'), $url)->toString();

    if ($status == SAVED_UPDATED) {
      // If we edited an existing entity...
      $this->messenger()->addMessage($this->t('Map %label has been updated.', ['%label' => $openlayers_map->label()]));
      $this->logger('contact')->notice('Map %label has been updated.', ['%label' => $openlayers_map->label(), 'link' => $edit_link]);
    }
    else {
      // If we created a new entity...
      $this->messenger()->addMessage($this->t('Map %label has been added.', ['%label' => $openlayers_map->label()]));
      $this->logger('contact')->notice('Map %label has been added.', ['%label' => $openlayers_map->label(), 'link' => $edit_link]);
    }

    // Redirect the user back to the listing route after the save operation
    $form_state->setRedirect('entity.openlayers_map.list');
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Update image effect weights.
    if (!$form_state->isValueEmpty('layers')) {
      $this->updateLayerWeights($form_state->getValue('layers'));
    }
  }

  /**
   * Validate handler for image effect.
   */
  public function objectValidate($form, FormStateInterface $form_state) {
    $type = str_replace('add_', '', $form_state->getTriggeringElement()['#name']);
    if (!$form_state->getValue('new_' . $type)) {
      $form_state->setErrorByName('new_' . $type, $this->t('Select a ' . $type . ' to add.'));
    }
  }

  /**
   * Submit handler for new/amended object being added to the map edit form.
   */
  public function objectSave($form, FormStateInterface $form_state) {

    $type = str_replace('add_', '', $form_state->getTriggeringElement()['#name']);

    //  Create empty Objects array if no layers added to map yet
    if ($this->entity->{$type . 's'} == '') {
      $this->entity->{$type . 's'} = [];
    }

    $this->save($form, $form_state);

    // Check if this field has any configuration options.
    //  TODO: potentially convert the config options to a plugin (see Image module in core with Styles/Effects as an example)
    //  TODO: there must be a shorthand for this eg. Node::load.

    $mapObject = \Drupal::entityTypeManager()
      ->getStorage('openlayers_' . $type)
      ->load($form_state->getValue('new_' . $type));

    // Load the configuration form for this option.
    if ($mapObject->get('is_configurable')) {
      $form_state->setRedirect(
        'openlayers.map.' . $type . '_add_form',
        [
          'map' => $this->entity->id(),
          $type => $form_state->getValue('new_' . $type),
          'weight' => $form_state->getValue('weight'),
        ],
        ['query' => ['weight' => $form_state->getValue('weight')]]
      );
    }
    // If there are no configuration options/form, add the new object to the map immediately.
    else {

      $configuration = [
        'id' => $mapObject->id(),
        'weight' => 0,
        'data' => ['entityId' => $mapObject->id()],
      ];    

      $form_state->setRedirect(
        'entity.openlayers_map.edit_form',
        [
          'openlayers_map' => $this->entity->id(),
        ],
      );

      $object_id = $this->entity->addMapObject($configuration, $type);

      $this->entity->save();
      if (!empty($object_id)) {
        $this->messenger()->addStatus($this->t('The ' . $type . ' was successfully added to the map.'));
      }
    }
  }

  /**
   * Validate handler for image effect.
   */
  public function layerValidate($form, FormStateInterface $form_state) {
    if (!$form_state->getValue('new_layer')) {
      $form_state->setErrorByName('new_layer', $this->t('Select a layer to add.'));
    }
  }

  /**
   * Submit handler for new/amended layer being added to the map edit form.
   */
  public function layerSave($form, FormStateInterface $form_state) {

    //  Create empty Layers array if no layers added to map yet
    if ($this->entity->layers == '') {
      $this->entity->layers = [];
    }

    $this->save($form, $form_state);

    // Check if this field has any configuration options.
    //  TODO: potentially convert the layer config options to a plugin (see Image module in core with Styles/Effects as an example)
    //  TODO: there must be a shorthand for this eg. Node::load.
    $layer = \Drupal::entityTypeManager()
      ->getStorage('openlayers_layer')
      ->load($form_state->getValue('new_layer'));

    // Load the configuration form for this option.
    if ($layer->get('is_configurable')) {
      $form_state->setRedirect(
        'openlayers.map.layer_add_form',
        [
          'map' => $this->entity->id(),
          'layer' => $form_state->getValue('new_layer'),
          'weight' => $form_state->getValue('weight'),
        ],
        ['query' => ['weight' => $form_state->getValue('weight')]]
      );
    }  
    // If there are no configuration options/form, add the layer to the map immediately.
    else {
      $configuration = [
        'id' => $layer->getType(),
        'weight' => 0,
        'data' => ['entityId' => $layer->id()],
      ];    

      $form_state->setRedirect(
        'entity.openlayers_map.edit_form',
        [
          'openlayers_map' => $this->entity->id(),
        ],
      );

      $object_id = $this->entity->addMapObject($configuration, $type);
      $this->entity->save();
      if (!empty($layer_id)) {
        $this->messenger()->addStatus($this->t('The ' . $type . ' was successfully added to the map.'));
      }
    }

  }

  /**
   * Validate handler for map style.
   */
  public function styleValidate($form, FormStateInterface $form_state) {
    if (!$form_state->getValue('new_style')) {
      $form_state->setErrorByName('new_style', $this->t('Select a style to add.'));
    }
  }

  /**
   * Submit handler for new/amended style being added to the map edit form.
   */
  public function styleSave($form, FormStateInterface $form_state) {
    $this->save($form, $form_state);

    // Check if this field has any configuration options.
    $style = $this->openlayersPluginManager->getDefinition($form_state->getValue('new_style'));

    // Load the configuration form for this option.
    if (is_subclass_of($style['class'], '\Drupal\openlayers\OpenlayersConfigurablePluginInterface')) {

      $form_state->setRedirect(
        'openlayers.style.plugin_add_form',
        [
          'map' => $this->entity->id(),
          'plugin_type' => 'style',
          'plugin' => $form_state->getValue('new_style'),
        ],

      );
    }  
    // If there are no configuration options/form, add the style to the map immediately.
    else {
      $style = [
        'id' => $style['id'],
        'data' => [],
        'weight' => 0,
        'data' => ['entityId' => $style->id()],
      ];
      $style_id = $this->entity->addMapStyle($style);
      $this->entity->save();
      if (!empty($style_id)) {
        $this->messenger()->addStatus($this->t('The style was successfully added to the map.'));
      }

      $form_state->setRedirect(
        'entity.openlayers_map.edit_form',
        [
          'openlayers_map' => $this->entity->id(),
        ],
      );
    }
  }

  /**
   * Validate handler for new/amended control.
   */
  public function controlValidate($form, FormStateInterface $form_state) {
    if (!$form_state->getValue('new_control')) {
      $form_state->setErrorByName('new_control', $this->t('Select a control to add.'));
    }
  }

  /**
   * Submit handler for new/amended layer being added to the map edit form.
   */
  public function controlSave($form, FormStateInterface $form_state) {

    $this->save($form, $form_state);

    // Check if this field has any configuration options.
    $control = $this->openlayersPluginManager->getDefinition($form_state->getValue('new_control'));

    // Load the configuration form for this option.
    if (is_subclass_of($control['class'], '\Drupal\openlayers\OpenlayersConfigurablePluginInterface')) {
      $form_state->setRedirect(
        'openlayers.control.plugin_add_form',
        [
          'map' => $this->entity->id(),
          'plugin_type' => 'control',
          'plugin' => $form_state->getValue('new_control'),
        ],
      );
    }  
    // If there are no configuration options/form, add the control to the map immediately.
    else {
      $control = [
        'id' => $control['id'],
        'data' => [],
        'weight' => 0,
        'data' => ['entityId' => $control['id']],
      ];
      $control_id = $this->entity->addMapControl($control);

      $this->entity->save();
      if (!empty($control_id)) {
        $this->messenger()->addStatus($this->t('The control was successfully added to the map.'));
      }

      $form_state->setRedirect(
        'entity.openlayers_map.edit_form',
        [
          'openlayers_map' => $this->entity->id(),
        ],
      );
    }
  }

  /**
   * Validate handler for image effect.
   */
  public function interactionValidate($form, FormStateInterface $form_state) {
    if (!$form_state->getValue('new_interaction')) {
      $form_state->setErrorByName('new_interaction', $this->t('Select a interaction to add.'));
    }
  }

  /**
   * Submit handler for new/amended interaction being added to the map edit form.
   */
  public function interactionSave($form, FormStateInterface $form_state) {

    $this->save($form, $form_state);

    // Check if this field has any configuration options.
    $interaction = $this->openlayersPluginManager->getDefinition($form_state->getValue('new_interaction'));


    // Load the configuration form for this option.

    if (is_subclass_of($interaction['class'], '\Drupal\openlayers\OpenlayersConfigurablePluginInterface')) {

      $form_state->setRedirect(
        'openlayers.interaction.plugin_add_form',
        [
          'map' => $this->entity->id(),
          'plugin_type' => 'interaction',
          'plugin' => $form_state->getValue('new_interaction'),
        ],
      );
    }  
    // If there are no configuration options/form, add the interaction to the map immediately.
    else {

      $interaction = [
        'id' => $interaction['id'],
        'data' => [],
        'weight' => 0,
        'data' => ['entityId' => $interaction->id()],
      ];

      $interaction_id = $this->entity->addMapInteraction($interaction);

      $this->entity->save();
      if (!empty($interaction_id)) {
        $this->messenger()->addStatus($this->t('The interaction was successfully added to the map.'));
      }

      $form_state->setRedirect(
        'entity.openlayers_map.edit_form',
        [
          'openlayers_map' => $this->entity->id(),
        ],
      );
    }
  }

  /**
   * Updates layer weights on map.
   *
   * @param array $layers
   *   Associative array with layers having layer uuid as keys and array
   *   with effect data as values.
   */
  protected function updateLayerWeights(array $layers) {
/*
    foreach ($layers as $uuid => $layer_data) {
      if (isset($this->entity->getLayers()[$uuid])) {
        $this->entity->layers[$uuid]['weight'] = $layer_data['weight'];
      }
    }
*/
  }
  
}

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

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