commercetools-8.x-1.2-alpha1/src/Plugin/Block/CommercetoolsProductFiltersBlockBase.php

src/Plugin/Block/CommercetoolsProductFiltersBlockBase.php
<?php

declare(strict_types=1);

namespace Drupal\commercetools\Plugin\Block;

use Drupal\commercetools\CommercetoolsService;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\InsertCommand;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines a base block implementation for product filters blocks.
 */
abstract class CommercetoolsProductFiltersBlockBase extends CommercetoolsCatalogActionBlockBase {

  /**
   * The commercetools service.
   *
   * @var \Drupal\commercetools\CommercetoolsService
   */
  protected CommercetoolsService $ct;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->ct = $container->get('commercetools');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state): array {
    $form = parent::blockForm($form, $form_state);
    $productTypes = $this->ct->getProductsTypes();
    $customFiltersID = Html::getUniqueId('custom-filters-table');

    $form['customize_filters_enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Customize Filters'),
      '#default_value' => $this->configuration['customize_filters_enabled'] ?? NULL,
    ];
    $form['customize_filters'] = [
      '#type' => 'details',
      '#title' => $this->t('Customize Filters'),
      '#open' => TRUE,
      '#attributes' => ['id' => [$customFiltersID]],
      '#states' => [
        'visible' => [
          ':input[name="settings[customize_filters_enabled]"]' => ['checked' => TRUE],
        ],
      ],
      'filters' => [
        '#type' => 'table',
        '#header' => [
          $this->t('Filter type'),
          $this->t('Filter name'),
          $this->t('Filter display label'),
          $this->t('Type'),
          $this->t('Path'),
          $this->t('Enabled'),
          $this->t('Actions'),
        ],
      ],
    ];

    foreach ($productTypes as $productTypeKey => $productType) {
      foreach ($productType['attributeDefinitions'] as $attributeKey => $attribute) {
        $productTypeNamesPerAttribute[$attributeKey][] = $productType['name'];
        $rowConfigs = $this->configuration['customize_filters'][$attributeKey] ?? [];

        $form['customize_filters']['filters'][$attributeKey] = $this->buildFilterRow('attribute', $rowConfigs, [
          'details' => [
            '#markup' => new FormattableMarkup('<div>@attrName</div><div class="form-item__description">@productTypeNames</div>', [
              '@attrName' => $attribute['label'],
              '@productTypeNames' => implode(', ', $productTypeNamesPerAttribute[$attributeKey]),
            ]),
          ],
          'label' => ['#default_value' => $rowConfigs['label'] ?? $attribute['label']],
          'widget_type' => [
            '#options' => [
              'facet' => $this->t('Facet'),
              'facet_count' => $this->t('Facet with count'),
            ],
            '#default_value' => $rowConfigs['widget_type'] ?? NULL,
          ],
          'path' => [
            '#disabled' => TRUE,
            '#value' => $this->ct->getAttributePath($productTypeKey, $attributeKey),
          ],
        ]);
      }
    }

    // Global filters.
    $filterConfig = $this->configuration['customize_filters']['show_in_stock_filter'] ?? [];
    $form['customize_filters']['filters']['show_in_stock_filter'] = $this->buildFilterRow('global', $filterConfig, [
      'details' => ['#markup' => $this->t('Show In Stock Filter')],
      'label' => ['#default_value' => $filterConfig['label'] ?? $this->t('In Stock')],
      'widget_type' => [
        '#options' => [
          'checkbox' => $this->t('Checkbox'),
        ],
      ],
      'path' => [
        '#disabled' => TRUE,
        '#value' => 'variants.availability.isOnStock',
      ],
    ]);

    $filterConfig = $this->configuration['customize_filters']['price_range_filter'] ?? [];
    $form['customize_filters']['filters']['price_range_filter'] = $this->buildFilterRow('global', $filterConfig, [
      'details' => ['#markup' => $this->t('Price Range Filter')],
      'label' => ['#default_value' => $filterConfig['label'] ?? $this->t('Price Range')],
      'widget_type' => [
        '#options' => [
          'custom' => $this->t('Custom'),
        ],
      ],
      'path' => [
        '#disabled' => TRUE,
        '#value' => 'variants.price.centAmount',
      ],
    ]);

    // Custom filters.
    $formStorage = $form_state->getStorage();
    $customFilters = array_filter($this->configuration['customize_filters'] ?? [], function ($filter) {
      return $filter['type'] === 'custom';
    });
    $formStorage['custom_filters'] = $formStorage['custom_filters'] ?? $customFilters;
    $form_state->setStorage($formStorage);
    foreach ($formStorage['custom_filters'] as $key => $filterConfig) {
      $form['customize_filters']['filters'][$key] = $this->buildFilterRow('custom', $filterConfig, [
        'details' => ['#markup' => $key],
        'enabled' => [
          '#default_value' => $filterConfig['enabled'] ?? TRUE,
        ],
        'actions' => [
          '#type' => 'actions',
          'remove' => [
            '#type' => 'submit',
            '#value' => $this->t('Remove'),
            '#limit_validation_errors' => [],
            '#submit' => [[$this, 'filterActionSubmit']],
            '#ajax' => [
              'callback' => [$this, 'filterActionAjax'],
              'wrapper' => $customFiltersID,
              'effect' => 'fade',
            ],
            '#name' => "remove:{$key}",
          ],
        ],
      ]);
    }
    $form['customize_filters']['add_filter'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add custom filter'),
      '#limit_validation_errors' => [],
      '#submit' => [[$this, 'filterActionSubmit']],
      '#name' => 'add',
      '#ajax' => [
        'callback' => [$this, 'filterActionAjax'],
        'wrapper' => $customFiltersID,
        'effect' => 'fade',
      ],
    ];
    return $form;
  }

  /**
   * Main method for building a filter form.
   */
  protected function buildFilterRow($filterType, $configs, $extra_settings = []): array {
    $extra_settings = $extra_settings + [
      'type' => [],
      'details' => [],
      'label' => [],
      'widget_type' => [],
      'path' => [],
      'enabled' => [],
      'actions' => [],
    ];

    return [
      'type' => $extra_settings['type'] + [
        '#type' => 'select',
        '#options' => [
          'global' => $this->t('Global'),
          'custom' => $this->t('Custom filter'),
          'attribute' => $this->t('Product attribute'),
        ],
        '#default_value' => $filterType,
        '#disabled' => TRUE,
      ],
      'details' => $extra_settings['details'],
      'label' => $extra_settings['label'] + [
        '#type' => 'textfield',
        '#default_value' => $configs['label'] ?? NULL,
        '#required' => TRUE,
      ],
      'widget_type' => $extra_settings['widget_type'] + [
        '#type' => 'select',
        '#options' => [
          'facet' => $this->t('Facet'),
          'facet_count' => $this->t('Facet with count'),
          'checkbox' => $this->t('Checkbox'),
          'textfield' => $this->t('Textfield'),
          'separator' => $this->t('Separator'),
        ],
        '#default_value' => $configs['widget_type'] ?? NULL,
      ],
      'path' => $extra_settings['path'] + [
        '#type' => 'textfield',
        '#default_value' => $configs['path'] ?? NULL,
        '#required' => TRUE,
      ],
      'enabled' => $extra_settings['enabled'] + [
        '#type' => 'checkbox',
        '#default_value' => $configs['enabled'] ?? FALSE,
      ],
      'actions' => $extra_settings['actions'],
    ];
  }

  /**
   * Ajax callback function for managing custom filters.
   */
  public function filterActionAjax(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new InsertCommand(NULL, $form['settings']['customize_filters']));
    return $response;
  }

  /**
   * Submit method for managing custom filters.
   */
  public function filterActionSubmit(array &$form, FormStateInterface $form_state) {
    $button = $form_state->getTriggeringElement();
    $formStorage = $form_state->getStorage();
    if ($button['#name'] === 'add') {
      if (empty($formStorage['custom_filters'])) {
        $index = 0;
      }
      else {
        [, $index] = explode('_', array_key_last($formStorage['custom_filters']));
        $index++;
      }
      $formStorage['custom_filters']["custom_{$index}"] = [];
    }
    else {
      [, $key] = explode(':', $button['#name']);
      unset($formStorage['custom_filters'][$key]);
    }
    $form_state->setStorage($formStorage);
    $form_state->setRebuild();
  }

  /**
   * {@inheritdoc}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['customize_filters_enabled'] = $form_state->getValue('customize_filters_enabled');
    $this->configuration['customize_filters'] = $this->configuration['customize_filters_enabled']
      ? $form_state->getValue('customize_filters')['filters']
      : NULL;
    parent::blockSubmit($form, $form_state);
  }

  /**
   * Get enabled filters.
   */
  protected function getEnabledFilters(): array {
    $filters = [];
    if (!empty($this->configuration['customize_filters_enabled'])) {
      foreach ($this->configuration['customize_filters'] as $filter) {
        if (!$filter['enabled']) {
          continue;
        }
        $filter['path'] = $this->ct->localizePath($filter['path']);
        if (in_array($filter['widget_type'], ['facet', 'facet_count'])) {
          $filter['graphql'] = $this->ct->buildFacetGraphql($filter['path'], $filter['widget_type'] === 'facet_count');
        }
        if ($filter['widget_type'] === 'custom') {
          $filter['graphql'] = $this->ct->buildRangeFacetGraphql($filter['path']);
        }
        if ($filter['type'] === 'attribute') {
          [,, $attributeKey] = explode('.', $filter['path']);
          $filter['attributeKey'] = $attributeKey;
        }
        $filters[] = $filter;
      }
    }
    else {
      $supportedTypes = ['enum', 'ltext', 'lenum'];
      $filterPaths = [];
      foreach ($this->ct->getProductsTypes() as $productTypeKey => $productType) {
        foreach ($productType['attributeDefinitions'] as $attributeKey => $attribute) {
          if (empty($attribute['isSearchable']) || !in_array($attribute['type'], $supportedTypes)) {
            continue;
          }

          $path = $this->ct->localizePath($this->ct->getAttributePath($productTypeKey, $attributeKey));
          if (in_array($path, $filterPaths)) {
            continue;
          }
          $filters[] = [
            'type' => 'attribute',
            'label' => $attribute['label'],
            'widget_type' => 'facet_count',
            'path' => $path,
            'graphql' => $this->ct->buildFacetGraphql($path, TRUE),
            'attributeKey' => $attributeKey,
          ];
          $filterPaths[] = $path;
        }
      }
      $filters[] = [
        'type' => 'attribute',
        'label' => $this->t('In Stock'),
        'widget_type' => 'checkbox',
        'path' => 'variants.availability.isOnStock',
      ];
      $filters[] = [
        'type' => 'attribute',
        'label' => $this->t('Price Range'),
        'widget_type' => 'custom',
        'path' => CommercetoolsService::CT_VARIANTS_PRICE_AMOUNT,
        'graphql' => $this->ct->buildRangeFacetGraphql(CommercetoolsService::CT_VARIANTS_PRICE_AMOUNT),
      ];
    }

    return $filters;
  }

}

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

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