You are here

class CouponRedemption in Commerce Core 8.2

Same name in this branch
  1. 8.2 modules/promotion/src/Plugin/views/area/CouponRedemption.php \Drupal\commerce_promotion\Plugin\views\area\CouponRedemption
  2. 8.2 modules/promotion/src/Plugin/Commerce/CheckoutPane/CouponRedemption.php \Drupal\commerce_promotion\Plugin\Commerce\CheckoutPane\CouponRedemption
  3. 8.2 modules/promotion/src/Plugin/Commerce/InlineForm/CouponRedemption.php \Drupal\commerce_promotion\Plugin\Commerce\InlineForm\CouponRedemption

Provides an inline form for redeeming a coupon.

Plugin annotation


@CommerceInlineForm(
  id = "coupon_redemption",
  label = @Translation("Coupon redemption"),
)

Hierarchy

Expanded class hierarchy of CouponRedemption

File

modules/promotion/src/Plugin/Commerce/InlineForm/CouponRedemption.php, line 20

Namespace

Drupal\commerce_promotion\Plugin\Commerce\InlineForm
View source
class CouponRedemption extends InlineFormBase {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a new CouponRedemption object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition, $container
      ->get('entity_type.manager'));
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      // The order_id is passed via configuration to avoid serializing the
      // order, which is loaded from scratch in the submit handler to minimize
      // chances of a conflicting save.
      'order_id' => '',
      // NULL for unlimited.
      'max_coupons' => NULL,
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function requiredConfiguration() {
    return [
      'order_id',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildInlineForm(array $inline_form, FormStateInterface $form_state) {
    $inline_form = parent::buildInlineForm($inline_form, $form_state);
    $order = $this->entityTypeManager
      ->getStorage('commerce_order')
      ->load($this->configuration['order_id']);
    if (!$order) {
      throw new \RuntimeException('Invalid order_id given to the coupon_redemption inline form.');
    }
    assert($order instanceof OrderInterface);

    /** @var \Drupal\commerce_promotion\Entity\CouponInterface[] $coupons */
    $coupons = $order
      ->get('coupons')
      ->referencedEntities();
    $inline_form = [
      '#tree' => TRUE,
      '#attached' => [
        'library' => [
          'commerce_promotion/coupon_redemption_form',
        ],
      ],
      '#theme' => 'commerce_coupon_redemption_form',
      '#configuration' => $this
        ->getConfiguration(),
    ] + $inline_form;
    $inline_form['code'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Coupon code'),
      // Chrome autofills this field with the address line 1, and ignores
      // autocomplete => 'off', but respects 'new-password'.
      '#attributes' => [
        'autocomplete' => 'new-password',
      ],
    ];
    $inline_form['apply'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Apply coupon'),
      '#name' => 'apply_coupon',
      '#limit_validation_errors' => [
        $inline_form['#parents'],
      ],
      '#submit' => [
        [
          get_called_class(),
          'applyCoupon',
        ],
      ],
      '#ajax' => [
        'callback' => [
          get_called_class(),
          'ajaxRefreshForm',
        ],
        'element' => $inline_form['#parents'],
      ],
    ];
    $max_coupons = $this->configuration['max_coupons'];
    if ($max_coupons && count($coupons) >= $max_coupons) {

      // Don't allow additional coupons to be added.
      $inline_form['code']['#access'] = FALSE;
      $inline_form['apply']['#access'] = FALSE;
    }
    foreach ($coupons as $index => $coupon) {
      $inline_form['coupons'][$index]['code'] = [
        '#plain_text' => $coupon
          ->getCode(),
      ];
      $inline_form['coupons'][$index]['display_name'] = [
        // @todo Use the promotion display name once added.
        '#plain_text' => $coupon
          ->getPromotion()
          ->label(),
      ];
      $inline_form['coupons'][$index]['remove_button'] = [
        '#type' => 'submit',
        '#value' => $this
          ->t('Remove coupon'),
        '#name' => 'remove_coupon_' . $index,
        '#ajax' => [
          'callback' => [
            get_called_class(),
            'ajaxRefreshForm',
          ],
          'element' => $inline_form['#parents'],
        ],
        '#weight' => 50,
        '#limit_validation_errors' => [
          $inline_form['#parents'],
        ],
        '#coupon_id' => $coupon
          ->id(),
        '#submit' => [
          [
            get_called_class(),
            'removeCoupon',
          ],
        ],
        // Simplify ajaxRefresh() by having all triggering elements
        // on the same level.
        '#parents' => array_merge($inline_form['#parents'], [
          'remove_coupon_' . $index,
        ]),
      ];
    }
    return $inline_form;
  }

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

    // Runs if the 'Apply coupon' button was clicked, or the main form
    // was submitted by the user clicking the primary submit button.
    $triggering_element = $form_state
      ->getTriggeringElement();
    $button_type = isset($triggering_element['#button_type']) ? $triggering_element['#button_type'] : NULL;
    if ($triggering_element['#name'] != 'apply_coupon' && $button_type != 'primary') {
      return;
    }
    $coupon_code_parents = array_merge($inline_form['#parents'], [
      'code',
    ]);
    $coupon_code = $form_state
      ->getValue($coupon_code_parents);
    $coupon_code_path = implode('][', $coupon_code_parents);
    if (empty($coupon_code)) {
      if ($triggering_element['#name'] == 'apply_coupon') {
        $form_state
          ->setErrorByName($coupon_code_path, t('Please provide a coupon code.'));
      }
      return;
    }

    /** @var \Drupal\commerce_promotion\CouponStorageInterface $coupon_storage */
    $coupon_storage = $this->entityTypeManager
      ->getStorage('commerce_promotion_coupon');
    $coupon = $coupon_storage
      ->loadEnabledByCode($coupon_code);
    if (empty($coupon)) {
      $form_state
        ->setErrorByName($coupon_code_path, t('The provided coupon code is invalid.'));
      return;
    }
    $order_storage = $this->entityTypeManager
      ->getStorage('commerce_order');

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $order_storage
      ->load($this->configuration['order_id']);
    foreach ($order
      ->get('coupons') as $item) {
      if ($item->target_id == $coupon
        ->id()) {

        // Coupon already applied. Error message not set for UX reasons.
        return;
      }
    }
    if (!$coupon
      ->available($order)) {
      $form_state
        ->setErrorByName($coupon_code_path, t('The provided coupon code is not available. It may have expired or already been used.'));
      return;
    }
    if (!$coupon
      ->getPromotion()
      ->applies($order)) {
      $form_state
        ->setErrorByName($coupon_code_path, t('The provided coupon code cannot be applied to your order.'));
      return;
    }

    // Save the coupon ID for applyCoupon.
    $inline_form['code']['#coupon_id'] = $coupon
      ->id();
  }

  /**
   * Submit callback for the "Apply coupon" button.
   */
  public static function applyCoupon(array $form, FormStateInterface $form_state) {
    $triggering_element = $form_state
      ->getTriggeringElement();
    $parents = array_slice($triggering_element['#parents'], 0, -1);
    $inline_form = NestedArray::getValue($form, $parents);

    // Clear the coupon code input.
    $user_input =& $form_state
      ->getUserInput();
    NestedArray::setValue($user_input, array_merge($parents, [
      'code',
    ]), '');
    if (isset($inline_form['code']['#coupon_id'])) {
      $order_storage = \Drupal::entityTypeManager()
        ->getStorage('commerce_order');

      /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
      $order = $order_storage
        ->load($inline_form['#configuration']['order_id']);
      $order
        ->get('coupons')
        ->appendItem($inline_form['code']['#coupon_id']);
      $order
        ->save();
    }
    $form_state
      ->setRebuild();
  }

  /**
   * Submit callback for the "Remove coupon" button.
   */
  public static function removeCoupon(array $form, FormStateInterface $form_state) {
    $triggering_element = $form_state
      ->getTriggeringElement();
    $parents = array_slice($triggering_element['#parents'], 0, -1);
    $inline_form = NestedArray::getValue($form, $parents);
    $order_storage = \Drupal::entityTypeManager()
      ->getStorage('commerce_order');

    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $order_storage
      ->load($inline_form['#configuration']['order_id']);
    $coupon_ids = array_column($order
      ->get('coupons')
      ->getValue(), 'target_id');
    $coupon_index = array_search($triggering_element['#coupon_id'], $coupon_ids);
    $order
      ->get('coupons')
      ->removeItem($coupon_index);
    $order
      ->save();
    $form_state
      ->setRebuild();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AjaxFormTrait::ajaxRefreshForm public static function Ajax handler for refreshing an entire form.
CouponRedemption::$entityTypeManager protected property The entity type manager.
CouponRedemption::applyCoupon public static function Submit callback for the "Apply coupon" button.
CouponRedemption::buildInlineForm public function Builds the inline form. Overrides InlineFormBase::buildInlineForm
CouponRedemption::create public static function Creates an instance of the plugin. Overrides InlineFormBase::create
CouponRedemption::defaultConfiguration public function Gets default configuration for this plugin. Overrides InlineFormBase::defaultConfiguration
CouponRedemption::removeCoupon public static function Submit callback for the "Remove coupon" button.
CouponRedemption::requiredConfiguration protected function Gets the required configuration for this plugin. Overrides InlineFormBase::requiredConfiguration
CouponRedemption::validateInlineForm public function Validates the inline form. Overrides InlineFormBase::validateInlineForm
CouponRedemption::__construct public function Constructs a new CouponRedemption object. Overrides InlineFormBase::__construct
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
InlineFormBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
InlineFormBase::getLabel public function Gets the inline form label. Overrides InlineFormInterface::getLabel
InlineFormBase::runSubmit public static function Runs the inline form submission.
InlineFormBase::runValidate public static function Runs the inline form validation.
InlineFormBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
InlineFormBase::submitInlineForm public function Submits the inline form. Overrides InlineFormInterface::submitInlineForm 4
InlineFormBase::updatePageTitle public static function Updates the page title based on the inline form's #page_title property.
InlineFormBase::validateConfiguration protected function Validates configuration. 1
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.