You are here

class CouponGenerateForm in Commerce Core 8.2

Provides a form for bulk generating coupons.

Hierarchy

Expanded class hierarchy of CouponGenerateForm

1 string reference to 'CouponGenerateForm'
commerce_promotion.routing.yml in modules/promotion/commerce_promotion.routing.yml
modules/promotion/commerce_promotion.routing.yml

File

modules/promotion/src/Form/CouponGenerateForm.php, line 16

Namespace

Drupal\commerce_promotion\Form
View source
class CouponGenerateForm extends FormBase {

  /**
   * The number of coupons to generate in each batch.
   *
   * @var int
   */
  const BATCH_SIZE = 25;

  /**
   * The maximum code length.
   *
   * @var int
   */
  const MAX_CODE_LENGTH = 255;

  /**
   * The coupon code generator.
   *
   * @var \Drupal\commerce_promotion\CouponCodeGeneratorInterface
   */
  protected $couponCodeGenerator;

  /**
   * The promotion.
   *
   * @var \Drupal\commerce_promotion\Entity\PromotionInterface
   */
  protected $promotion;

  /**
   * Constructs a new CouponGenerateForm object.
   *
   * @param \Drupal\commerce_promotion\CouponCodeGeneratorInterface $coupon_code_generator
   *   The coupon code generator.
   * @param \Drupal\Core\Routing\CurrentRouteMatch $current_route_match
   *   The current route match.
   */
  public function __construct(CouponCodeGeneratorInterface $coupon_code_generator, CurrentRouteMatch $current_route_match) {
    $this->couponCodeGenerator = $coupon_code_generator;
    $this->promotion = $current_route_match
      ->getParameter('commerce_promotion');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container
      ->get('commerce_promotion.coupon_code_generator'), $container
      ->get('current_route_match'));
  }

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

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['quantity'] = [
      '#type' => 'number',
      '#title' => $this
        ->t('Number of coupons'),
      '#required' => TRUE,
      '#default_value' => '10',
      '#min' => 1,
      '#max' => 1000,
      '#step' => 1,
    ];
    $form['pattern'] = [
      '#type' => 'fieldset',
      '#title' => $this
        ->t('Coupon code pattern'),
    ];
    $form['pattern']['format'] = [
      '#type' => 'select',
      '#title' => $this
        ->t('Format'),
      '#required' => TRUE,
      '#options' => [
        'alphanumeric' => $this
          ->t('Alphanumeric'),
        'alphabetic' => $this
          ->t('Alphabetic'),
        'numeric' => $this
          ->t('Numeric'),
      ],
      '#default_value' => 'alphanumeric',
    ];
    $form['pattern']['prefix'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Prefix'),
      '#size' => 20,
    ];
    $form['pattern']['suffix'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Suffix'),
      '#size' => 20,
    ];
    $form['pattern']['length'] = [
      '#type' => 'number',
      '#title' => $this
        ->t('Length'),
      '#description' => $this
        ->t('Length does not include prefix/suffix.'),
      '#required' => TRUE,
      '#default_value' => 8,
      '#min' => 1,
    ];
    $form['limit'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('Number of uses per coupon'),
      '#options' => [
        0 => $this
          ->t('Unlimited'),
        1 => $this
          ->t('Limited number of uses'),
      ],
      '#default_value' => 1,
    ];
    $form['usage_limit'] = [
      '#type' => 'number',
      '#title' => $this
        ->t('Number of uses'),
      '#title_display' => 'invisible',
      '#default_value' => 1,
      '#min' => 1,
      '#states' => [
        'invisible' => [
          ':input[name="limit"]' => [
            'value' => 0,
          ],
        ],
      ],
    ];
    $form['limit_customer'] = [
      '#type' => 'radios',
      '#title' => $this
        ->t('Number of uses per customer per coupon'),
      '#options' => [
        0 => $this
          ->t('Unlimited'),
        1 => $this
          ->t('Limited number of uses'),
      ],
      '#default_value' => 1,
    ];
    $form['usage_limit_customer'] = [
      '#type' => 'number',
      '#title' => $this
        ->t('Number of uses per customer'),
      '#title_display' => 'invisible',
      '#default_value' => 1,
      '#min' => 1,
      '#states' => [
        'invisible' => [
          ':input[name="limit_customer"]' => [
            'value' => 0,
          ],
        ],
      ],
    ];
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this
        ->t('Generate'),
      '#button_type' => 'primary',
    ];
    return $form;
  }

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

    // Make sure that the total length doesn't exceed the database limit.
    $code_length = strlen($values['prefix']) + strlen($values['suffix']) + $values['length'];
    if ($code_length > self::MAX_CODE_LENGTH) {
      $form_state
        ->setError($form['pattern'], $this
        ->t('The total pattern length (@coupon_length) exceeds the maximum length allowed (@max_length).', [
        '@coupon_length' => $code_length,
        '@max_length' => self::MAX_CODE_LENGTH,
      ]));
    }

    // Validate that pattern for the given quantity.
    $quantity = $values['quantity'];
    $pattern = new CouponCodePattern($values['format'], $values['prefix'], $values['suffix'], $values['length']);
    if (!$this->couponCodeGenerator
      ->validatePattern($pattern, $quantity)) {
      $form_state
        ->setError($form['pattern'], $this
        ->t('This pattern cannot be used to generate @quantity coupons.', [
        '@quantity' => $quantity,
      ]));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state
      ->getValues();
    $quantity = $values['quantity'];
    $coupon_values = [
      'promotion_id' => $this->promotion
        ->id(),
      'usage_limit' => $values['limit'] ? $values['usage_limit'] : 0,
      'usage_limit_customer' => $values['usage_limit_customer'],
    ];
    $pattern = new CouponCodePattern($values['format'], $values['prefix'], $values['suffix'], $values['length']);
    $batch_builder = (new BatchBuilder())
      ->setTitle($this
      ->t('Generating coupons'))
      ->setProgressMessage('')
      ->setFinishCallback([
      $this,
      'finishBatch',
    ])
      ->addOperation([
      get_class($this),
      'processBatch',
    ], [
      $quantity,
      $coupon_values,
      $pattern,
    ]);
    batch_set($batch_builder
      ->toArray());
    $form_state
      ->setRedirect('entity.commerce_promotion_coupon.collection', [
      'commerce_promotion' => $this->promotion
        ->id(),
    ]);
  }

  /**
   * Processes the batch and generates the coupons.
   *
   * @param int $quantity
   *   The number of coupons to generate.
   * @param string[] $coupon_values
   *   The initial coupon entity values.
   * @param \Drupal\commerce_promotion\CouponCodePattern $pattern
   *   The pattern.
   * @param array $context
   *   The batch context information.
   */
  public static function processBatch($quantity, array $coupon_values, CouponCodePattern $pattern, array &$context) {
    if (empty($context['sandbox'])) {
      $context['sandbox']['total_quantity'] = (int) $quantity;
      $context['sandbox']['created'] = 0;
      $context['results']['codes'] = [];
      $context['results']['total_quantity'] = $quantity;
    }
    $total_quantity = $context['sandbox']['total_quantity'];
    $created =& $context['sandbox']['created'];
    $remaining = $total_quantity - $created;
    $coupon_storage = \Drupal::entityTypeManager()
      ->getStorage('commerce_promotion_coupon');
    $limit = $remaining < self::BATCH_SIZE ? $remaining : self::BATCH_SIZE;
    $coupon_code_generator = \Drupal::service('commerce_promotion.coupon_code_generator');
    $codes = $coupon_code_generator
      ->generateCodes($pattern, $limit);
    if (!empty($codes)) {
      foreach ($codes as $code) {
        $coupon = $coupon_storage
          ->create([
          'code' => $code,
        ] + $coupon_values);
        $coupon
          ->save();
        $context['results']['codes'][] = $code;
        $created++;
      }
      $context['message'] = t('Creating coupon @created of @total_quantity', [
        '@created' => $created,
        '@total_quantity' => $total_quantity,
      ]);
      $context['finished'] = $created / $total_quantity;
    }
    else {
      $context['finished'] = 1;
    }
  }

  /**
   * Batch finished callback: display batch statistics.
   *
   * @param bool $success
   *   Indicates whether the batch has completed successfully.
   * @param mixed[] $results
   *   The array of results gathered by the batch processing.
   * @param string[] $operations
   *   If $success is FALSE, contains the operations that remained unprocessed.
   */
  public static function finishBatch($success, array $results, array $operations) {
    if ($success) {
      $created = count($results['codes']);

      // An incomplete set of coupons was generated.
      if ($created != $results['total_quantity']) {
        \Drupal::messenger()
          ->addWarning(t('Generated %created out of %total requested coupons. Consider adding a unique prefix/suffix or increasing the pattern length to improve results.', [
          '%created' => $created,
          '%total' => $results['total_quantity'],
        ]));
      }
      else {
        \Drupal::messenger()
          ->addMessage(\Drupal::translation()
          ->formatPlural($created, 'Generated 1 coupon.', 'Generated @count coupons.'));
      }
    }
    else {
      $error_operation = reset($operations);
      \Drupal::messenger()
        ->addError(t('An error occurred while processing @operation with arguments: @args', [
        '@operation' => $error_operation[0],
        '@args' => print_r($error_operation[0], TRUE),
      ]));
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CouponGenerateForm::$couponCodeGenerator protected property The coupon code generator.
CouponGenerateForm::$promotion protected property The promotion.
CouponGenerateForm::BATCH_SIZE constant The number of coupons to generate in each batch.
CouponGenerateForm::buildForm public function Form constructor. Overrides FormInterface::buildForm
CouponGenerateForm::create public static function Instantiates a new instance of this class. Overrides FormBase::create
CouponGenerateForm::finishBatch public static function Batch finished callback: display batch statistics.
CouponGenerateForm::getFormId public function Returns a unique string identifying the form. Overrides FormInterface::getFormId
CouponGenerateForm::MAX_CODE_LENGTH constant The maximum code length.
CouponGenerateForm::processBatch public static function Processes the batch and generates the coupons.
CouponGenerateForm::submitForm public function Form submission handler. Overrides FormInterface::submitForm
CouponGenerateForm::validateForm public function Form validation handler. Overrides FormBase::validateForm
CouponGenerateForm::__construct public function Constructs a new CouponGenerateForm object.
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
FormBase::$configFactory protected property The config factory. 1
FormBase::$requestStack protected property The request stack. 1
FormBase::$routeMatch protected property The route match.
FormBase::config protected function Retrieves a configuration object.
FormBase::configFactory protected function Gets the config factory for this form. 1
FormBase::container private function Returns the service container.
FormBase::currentUser protected function Gets the current user.
FormBase::getRequest protected function Gets the request object.
FormBase::getRouteMatch protected function Gets the route match.
FormBase::logger protected function Gets the logger for a specific channel.
FormBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
FormBase::resetConfigFactory public function Resets the configuration factory.
FormBase::setConfigFactory public function Sets the config factory for this form.
FormBase::setRequestStack public function Sets the request stack object to use.
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
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.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.