search_web_components-1.0.x-dev/modules/facets/src/Form/FacetForm.php

modules/facets/src/Form/FacetForm.php
<?php

namespace Drupal\search_web_components_facets\Form;

use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\facets\Form\FacetForm as SourceFacetForm;
use Drupal\facets\Processor\SortProcessorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Provides a form for configuring the processors of a facet.
 */
class FacetForm extends SourceFacetForm {

  const NONSWC_SETTINGS = ['settings'];
  const INTERFACE_SETTINGS = ['settings', 'interface_settings'];
  const INTERFACE_FACET_SETTINGS = ['settings', 'interface_settings', 'facet_settings'];

  const PROCESSING_SETTINGS = ['settings', 'processing_settings'];
  const UNSUPPORTED_SETTINGS = ['settings', 'unsupported_settings'];
  const ADVANCED_SETTINGS = ['settings', 'advanced_settings'];

  /**
   * Map each facet field to a new home in the vertical tabs.
   *
   * @var array[]
   */
  protected $fieldMetaData = [
    'widget_config' => [
      'parents' => self::INTERFACE_SETTINGS,
    ],
    'show_title' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'url_alias' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'hide_active_items_processor' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'hide_non_narrowing_result_processor' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'show_only_one_result' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'query_operator' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'hard_limit' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'empty_behavior' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'empty_behavior_container' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'missing' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'missing_label' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'use_hierarchy' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'hierarchy' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'keep_hierarchy_parents_active' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'expand_hierarchy' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'enable_parent_when_child_gets_disabled' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'hide_inactive_siblings_processor' => [
      'parents' => self::INTERFACE_FACET_SETTINGS,
    ],
    'facet_sorting' => [
      'parents' => self::INTERFACE_SETTINGS,
    ],

    'boolean_item' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'combine_processor' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'count_limit' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'dependent_processor' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'exclude_specified_items' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'granularity_item' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'hide_1_result_facet' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'list_item' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'replace' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'show_only_deepest_level_items_processor' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'show_siblings_processor' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'translate_entity' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'translate_entity_aggregated_fields' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'exclude' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'min_count' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],
    'uid_to_username_callback' => [
      'parents' => self::PROCESSING_SETTINGS,
    ],

    'date_item' => [
      'parents' => self::UNSUPPORTED_SETTINGS,
    ],
    'only_visible_when_facet_source_is_visible' => [
      'parents' => self::UNSUPPORTED_SETTINGS,
    ],
    'weight' => [
      'parents' => self::UNSUPPORTED_SETTINGS,
    ],
    'hierarchy_processor' => [
      'parents' => self::UNSUPPORTED_SETTINGS,
    ],
    'url_processor_handler' => [
      'parents' => self::UNSUPPORTED_SETTINGS,
    ],

    'weights' => [
      'parents' => self::ADVANCED_SETTINGS,
    ],
  ];

  /**
   * The current route.
   *
   * @var \Drupal\Core\Routing\CurrentRouteMatch
   */
  protected $routeMatch;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->injectServices($container);

    return $instance;
  }

  /**
   * Inject additional required services.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The container to pull out services used in the plugin.
   */
  public function injectServices(ContainerInterface $container): void {
    $this->routeMatch = $container->get('current_route_match');
  }

  /**
   * {@inheritdoc}
   */
  public function buildWidgetConfigForm(array &$form, FormStateInterface $form_state) {
    parent::buildWidgetConfigForm($form, $form_state);
    // Tweak widget config settings to better fit the new structure.
    $form['widget_config']['#type'] = 'details';
    $form['widget_config']['#open'] = TRUE;
    $form['widget_config']['#description'] = $this->t('Settings specific to this widget.');

    // Update the AJAX config to replace the whole form when a widget is
    // changed.
    $form['widget']['#ajax']['callback'] = '::buildAjaxSettingsForm';
    $form['widget']['#ajax']['wrapper'] = 'facets-settings-form';

    $form['widget_configure_button']['#ajax']['callback'] = '::buildAjaxSettingsForm';
    $form['widget_configure_button']['#ajax']['wrapper'] = 'facets-settings-form';
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);
    // Redirect to facets settings page if Field Identifier is not set.
    if ($facets = $this->routeMatch->getParameter('facets_facet')) {
      if ($facets->getFieldIdentifier() === NULL) {
        $facet_settings_path = $facets->toUrl('settings-form')->toString();
        $response = new RedirectResponse($facet_settings_path);
        $response->send();
        return [];
      }
    }

    /** @var \Drupal\facets\FacetInterface $facet */
    $facet = $this->entity;

    // Add a new container to target with AJAX.
    $form['settings'] = [
      '#id' => 'facets-settings-form',
      '#type' => 'container',
    ];

    // Move non SWC provided forms to support AJAX replacing of the entire form
    // instead of just widgets.
    if (!str_contains($facet->getWidget()['type'], 'swc_')) {
      foreach ($form['facet_settings'] as &$element) {
        if (is_array($element)) {
          $this->updateStateConditions($element, array_merge(self::NONSWC_SETTINGS, ['facet_settings']));
        }
      }
      $form['settings']['widget_config'] = $form['widget_config'];
      $form['settings']['facet_settings'] = $form['facet_settings'];
      $form['settings']['facet_sorting'] = $form['facet_sorting'];
      $form['settings']['weights'] = $form['weights'];
      $form['settings']['processor_settings'] = $form['processor_settings'];

      unset($form['widget_config']);
      unset($form['facet_settings']);
      unset($form['facet_sorting']);
      unset($form['weights']);
      unset($form['processor_settings']);

      $form_state->set('swcForm', FALSE);
      return $form;
    }
    $form_state->set('swcForm', TRUE);
    $source_facet_settings = [];

    // Setup all the vertical tab containers.
    $form['settings']['settings_tabs'] = [
      '#type' => 'vertical_tabs',
      '#attributes' => [
        'class' => [
          'search-api-status-wrapper',
        ],
      ],
    ];
    $form['settings']['interface_settings'] = [
      '#type' => 'details',
      '#group' => 'settings][settings_tabs',
      '#title' => $this->t('Interface settings'),
      '#description' => $this->t('These settings relate to how the facet displays or how a user can interact with the facet.'),
    ];
    $form['settings']['processing_settings'] = [
      '#type' => 'details',
      '#group' => 'settings][settings_tabs',
      '#title' => $this->t('Processing settings'),
      '#description' => $this->t('These settings relate to when a facet is displayed and how a facet is processed by the server before responding to a search query.'),
    ];
    $form['settings']['advanced_settings'] = [
      '#type' => 'details',
      '#group' => 'settings][settings_tabs',
      '#title' => $this->t('Advanced settings'),
    ];
    $form['settings']['unsupported_settings'] = [
      '#type' => 'details',
      '#group' => 'settings][settings_tabs',
      '#title' => $this->t('Unsupported settings'),
    ];

    // Add containers inside interface settings to ensure the right order and
    // so individual values can be grouped.
    $form['settings']['interface_settings']['widget_config'] = [];
    $form['settings']['interface_settings']['facet_settings'] = [
      '#type' => 'details',
      '#open' => TRUE,
      '#title' => $this->t('Additional settings'),
      '#description' => $this->t('Additional facet settings that are available to all facets.'),
    ];

    // Tweak processor ordering to better fit the new structure.
    $form['weights']['#title'] = $this->t('Processor order');
    $form['weights']['#type'] = 'details';
    $form['weights']['#open'] = TRUE;
    unset($form['weights']['order']);

    // Tweak facet sorting to better fit the new structure.
    $form['facet_sorting']['#type'] = 'details';
    $form['facet_sorting']['#description'] = $this->t('Change how the facet options are ordered when displayed to the user.');
    $form['facet_sorting']['#open'] = TRUE;

    // Move all the elements to their correct tab and remove the original
    // element definition.
    foreach ($this->fieldMetaData as $element => $metadata) {
      $form_element = NULL;
      if (isset($form[$element])) {
        $form_element = $form[$element];
        unset($form[$element]);
      }
      elseif (isset($form['facet_settings'][$element])) {
        $source_facet_settings[] = $element;
        $form_element = $form['facet_settings'][$element];
        unset($form['facet_settings'][$element]);
      }

      if ($form_element) {
        $parents = array_merge($metadata['parents'], [$element]);
        $this->updateStateConditions($form_element, $metadata['parents']);
        NestedArray::setValue($form, $parents, $form_element, TRUE);
      }

    }
    $form_state->set('source_facet_settings', $source_facet_settings);

    $form['facet_settings']['#type'] = 'container';

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    /** @var \Drupal\facets\FacetInterface $facet */
    $facet = $this->entity;

    $values = $form_state->getValues();
    /** @var \Drupal\facets\Processor\ProcessorInterface[] $processors */
    $processors = $facet->getProcessors(FALSE);

    // Locate and iterate over all processors.
    if ($form_state->get('swcForm')) {
      $facet_settings = $form_state->get('source_facet_settings');
    }
    else {
      $facet_settings = array_keys($form['settings']['facet_settings']);
    }
    foreach ($facet_settings as $pid) {
      $processor_id = $pid;

      if (empty($values['processors'][$processor_id])) {
        continue;
      }

      if ($form_state->get('swcForm')) {
        $path = array_merge($this->fieldMetaData[$pid]['parents'], [$pid]);
      }
      else {
        $path = array_merge(self::NONSWC_SETTINGS, [$pid]);
      }

      $processor_form = NestedArray::getValue($form, $path);
      $value = $form_state->getValue($path);

      if (!empty($value)) {
        $processor_form_state = SubformState::createForSubform($processor_form['settings'], $form, $form_state);
        $processors[$processor_id]->validateConfigurationForm($processor_form, $processor_form_state, $facet);
      }
    }

    // Locate and iterate over all sorting processors that have a form and
    // are enabled.
    if ($form_state->get('swcForm')) {
      $facet_sorting = NestedArray::getValue($form, array_merge($this->fieldMetaData['facet_sorting']['parents'], ['facet_sorting']));
    }
    else {
      $facet_sorting = NestedArray::getValue($form, array_merge(self::NONSWC_SETTINGS, ['facet_sorting']));
    }
    foreach ($facet_sorting as $processor_id => $processor_form) {
      if (!empty($values['processors'][$processor_id])) {
        $processor_form_state = SubformState::createForSubform($facet_sorting[$processor_id]['settings'], $form, $form_state);
        $processors[$processor_id]->validateConfigurationForm($facet_sorting[$processor_id], $processor_form_state, $facet);
      }
    }

    // Validate url alias.
    if ($form_state->get('swcForm')) {
      $url_alias = NestedArray::getValue($values, array_merge($this->fieldMetaData['url_alias']['parents'], ['url_alias']));
    }
    else {
      $url_alias = NestedArray::getValue($values, array_merge(self::NONSWC_SETTINGS, ['facet_settings', 'url_alias']));
    }

    if ($url_alias === 'page') {
      $form_state->setErrorByName('url_alias', $this->t('This URL alias is not allowed.'));
    }
    elseif (preg_match('/[^a-zA-Z0-9_~.\-]/', $url_alias)) {
      $form_state->setErrorByName('url_alias', $this->t('The URL alias contains characters that are not allowed.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();

    if ($form_state->get('swcForm')) {
      $form_state->setValue('processor_settings', $values['processor_settings']);
      $source_facet_settings = $form_state->get('source_facet_settings');
      $facet_settings_values = [];
      foreach ($this->fieldMetaData as $field => $metadata) {
        if (in_array($field, $source_facet_settings)) {
          $facet_settings_values[$field] = NestedArray::getValue($values, array_merge($metadata['parents'], [$field]));
        }
        else {
          $form_state->setValue($field, NestedArray::getValue($values, array_merge($metadata['parents'], [$field])));
        }
      }
      $form_state->setValue('facet_settings', $facet_settings_values);

    }
    else {
      $form_state->setValue('widget_config', $values['settings']['widget_config']);
      $form_state->setValue('facet_settings', $values['settings']['facet_settings']);
      $form_state->setValue('facet_sorting', $values['settings']['facet_sorting']);
      $form_state->setValue('weights', $values['settings']['weights']);
      $form_state->setValue('processor_settings', $values['settings']['processor_settings']);
    }
    // Let the facets class do the majority of the saving work.
    parent::submitForm($form, $form_state);
    $values = $form_state->getValues();

    // Store processor settings.
    /** @var \Drupal\facets\FacetInterface $facet */
    $facet = $this->entity;

    /** @var \Drupal\facets\Processor\ProcessorInterface $processor */
    $processors = $facet->getProcessors(FALSE);
    foreach ($processors as $processor_id => $processor) {
      $form_container_key = $processor instanceof SortProcessorInterface ? 'facet_sorting' : 'facet_settings';

      $path = '';
      if ($form_state->get('swcForm')) {
        if ($form_container_key === 'facet_sorting') {
          $path = array_merge($this->fieldMetaData['facet_sorting']['parents'], ['facet_sorting', $processor_id]);
        }
        elseif (isset($this->fieldMetaData[$processor_id]['parents'])) {
          $path = array_merge($this->fieldMetaData[$processor_id]['parents'] ?? [], [$processor_id]);
        }
      }
      else {
        $path = array_merge(self::NONSWC_SETTINGS, [$form_container_key, $processor_id]);
      }

      if (!$path || empty(NestedArray::getValue($values, array_merge($path, ['status'])))) {
        $facet->removeProcessor($processor_id);
        continue;
      }
      $new_settings = [
        'processor_id' => $processor_id,
        'weights' => [],
        'settings' => [],
      ];
      if (!empty($values['processors'][$processor_id]['weights'])) {
        $new_settings['weights'] = $values['processors'][$processor_id]['weights'];
      }

      $element = NestedArray::getValue($form, array_merge($path, ['settings']));
      if ($element) {
        $processor_form_state = SubformState::createForSubform($element, $form, $form_state);
        $processor->submitConfigurationForm($element, $processor_form_state, $facet);
        $new_settings['settings'] = $processor->getConfiguration();
      }
      $facet->addProcessor($new_settings);
    }

    $facet->save();
  }

  /**
   * Handles changes to the settings when the widget changes.
   */
  public function buildAjaxSettingsForm(array $form, FormStateInterface $form_state) {
    return $form['settings'];
  }

  /**
   * Recursively update the #states attribute with the provided parent path.
   */
  protected function updateStateConditions(array &$element, array $parents): void {
    $p = $parents;
    if (count($parents) === 1) {
      $new_parents = reset($p);
    }
    else {
      $new_parents = array_shift($p) . '[';
      $new_parents .= implode("][", $p) . ']';
    }

    foreach ($element as $key => &$item) {
      if ($key === '#states') {
        foreach ($item as $state => &$conditions) {
          foreach ($conditions as $condition => $value) {
            $new_condition = str_replace(
              'name="facet_settings',
              'name="' . $new_parents,
              $condition,
            );
            $conditions[$new_condition] = $value;
            unset($element[$key][$state][$condition]);
          }
        }
      }
      elseif (is_array($item)) {
        $this->updateStateConditions($item, $parents);
      }
    }
  }

}

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

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