commercetools-8.x-1.2-alpha1/modules/commercetools_content/src/Form/AddToCartForm.php

modules/commercetools_content/src/Form/AddToCartForm.php
<?php

namespace Drupal\commercetools_content\Form;

use Drupal\commercetools\CommercetoolsCarts;
use Drupal\commercetools\CommercetoolsService;
use Drupal\commercetools\Routing\UiModulesRouteProviderBase;
use Drupal\commercetools_content\Routing\RouteProvider;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Security\TrustedCallbackInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides add to cart form.
 */
class AddToCartForm extends FormBase implements TrustedCallbackInterface {

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

  /**
   * The commercetools cart service.
   *
   * @var \Drupal\commercetools\CommercetoolsCarts
   */
  protected CommercetoolsCarts $ctCart;

  /**
   * Array of product types.
   *
   * @var array
   */
  protected array $productTypes;

  /**
   * Current product.
   *
   * @var array
   */
  protected array $product;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->ct = $container->get('commercetools');
    $instance->ctCart = $container->get('commercetools.carts');
    $instance->productTypes = $instance->ct->getProductsTypes();

    return $instance;
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $install_state = NULL) {
    [$this->product] = $form_state->getBuildInfo()['args'];

    $currentVariant = $form_state->isValueEmpty('product_attributes')
      ? $this->getCurrentVariant(['sku' => $this->product['current_sku']])
      : $this->getCurrentVariant(['attributes' => $form_state->getValue('product_attributes')]);

    $attributes = $this->getEnabledProductAttributes();
    uasort($attributes, function ($attr1) {
      return count($attr1['options']) > 1 ? 1 : -1;
    });

    $form['#theme'] = 'commercetools_add_to_cart_form';
    $form['#attributes'] = [
      'id' => ['product-add-to-cart-form'],
      'class' => ['add-to-cart-form'],
    ];
    $form['product_display'] = [
      '#theme' => 'commercetools_product_page',
      '#product' => array_merge($this->product, $currentVariant, ['id' => $this->product['id']]),
      '#unavailable_data_text' => $this->config(CommercetoolsService::CONFIGURATION_NAME)->get(CommercetoolsService::CONFIG_UNAVAILABLE_DATA_TEXT),
      '#attributes' => [
        'class' => ['my-4'],
      ],
    ];

    $form['product_attributes'] = [
      '#type' => 'container',
      '#tree' => TRUE,
      '#attributes' => [
        'class' => ['product__variants', 'row'],
      ],
    ];

    foreach ($attributes as $attrName => $attr) {
      if (count($attr['options']) > 1) {
        $defaultValue = $currentVariant['attributes'][$attrName]['value'] ?? NULL;
        $form['product_attributes'][$attrName] = [
          '#type' => 'select',
          '#pre_render' => [static::class . '::buildProductAttributeFormElement'],
          '#attributes' => ['class' => ['w-50']],
          '#title' => new FormattableMarkup('<span class="fw-medium align-self-center">@label</span>', [
            '@label' => $attr['label'],
          ]),
          '#options' => $attr['options'],
          '#default_value' => $defaultValue,
          '#ajax' => [
            'callback' => '::ajaxCallback',
            'disable-refocus' => FALSE,
            'event' => 'change',
            'wrapper' => 'product-add-to-cart-form',
            'progress' => [
              'type' => 'throbber',
              'message' => $this->t('Updating...'),
            ],
          ],
        ];
      }
      else {
        $value = reset($attr['options']);
        $form['product_attributes'][$attrName] = [
          '#theme' => 'commercetools_product_attribute',
          '#label' => $attr['label'],
          '#value' => [
            '#theme' => 'commercetools_product_attribute_label',
            '#key' => $attrName,
            '#label' => $value,
          ],
        ];
      }
    }
    $form['sku'] = [
      '#type' => 'hidden',
      '#value' => $currentVariant['sku'],
    ];
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add to Cart'),
      '#disabled' => empty($currentVariant['availability']),
      '#attributes' => ['class' => ['btn-lg']],
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public static function trustedCallbacks() {
    return ['buildProductAttributeFormElement'];
  }

  /**
   * Replace default form element wrapper.
   */
  public static function buildProductAttributeFormElement(array $build) {
    $build['#theme_wrappers'] = ['commercetools_product_attribute_form_element'];
    return $build;
  }

  /**
   * Ajax callback to update product variant.
   */
  public function ajaxCallback(array &$form, FormStateInterface $form_state) {
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $cartResponse = $this->ctCart->getCurrentCart();
    if (empty($cartResponse)) {
      $cartResponse = $this->ctCart->createCart([
        'lineItems' => [['quantity' => 1, 'sku' => $form_state->getValue('sku')]],
      ]);
      $this->ctCart->setCurrentCart($cartResponse->getData());
    }
    else {
      $cart = $cartResponse->getData();
      $actions = [['addLineItem' => ['quantity' => 1, 'sku' => $form_state->getValue('sku')]]];
      $this->ctCart->updateCart($cart['id'], $cart['version'], $actions);
    }

    [$product] = $form_state->getBuildInfo()['args'];
    $this->messenger()->addMessage(new FormattableMarkup("@product_name added to @cart.", [
      '@product_name' => $product['name'],
      '@cart' => Link::createFromRoute('cart', RouteProvider::ROUTE_PREFIX . UiModulesRouteProviderBase::PAGE_CART_ROUTE)->toString(),
    ]));

  }

  /**
   * Get enabled product attributes.
   *
   * @return array
   *   An array of all enabled attribute options.
   */
  protected function getEnabledProductAttributes(): array {
    $attrVariants = [];

    $productType = $this->product['type']['key'];
    if (empty($this->ct->getEnabledAttributes()[$productType])) {
      return $attrVariants;
    }
    $allVariants = array_merge($this->product['variants'], [$this->product['masterVariant']]);
    foreach ($this->ct->getEnabledAttributes()[$productType] as $attr) {
      $attrName = $attr['name'];
      $attrVariants[$attrName] = [
        'label' => $attr['label'],
        'options' => [],
      ];
      foreach ($allVariants as $variant) {
        if (!empty($variant['attributes'][$attrName])) {
          $value = $variant['attributes'][$attrName]['value'];
          $attrVariants[$attrName]['options'][$value] = $variant['attributes'][$attrName]['labelValue'];
        }
      }
    }

    return $attrVariants;
  }

  /**
   * Get current product variant.
   *
   * @param array $variantArgs
   *   An array of args to find necessary variant.
   *
   * @return array
   *   The variant according to args.
   */
  protected function getCurrentVariant(array $variantArgs): array {
    if (empty($variantArgs['sku']) && empty($variantArgs['attributes'])) {
      return $this->product['masterVariant'];
    }

    foreach ($this->product['variants'] as $variant) {
      if (isset($variantArgs['sku']) && $variantArgs['sku'] != $variant['sku']) {
        continue;
      }
      if (isset($variantArgs['attributes'])) {
        foreach ($variantArgs['attributes'] as $attrName => $attrValue) {
          $variantValue = $variant['attributes'][$attrName]['value'] ?? NULL;
          if ($variantValue !== $attrValue) {
            continue 2;
          }
        }
      }
      return $variant;
    }

    return $this->product['masterVariant'];
  }

}

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

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