auctions-1.0.x-dev/modules/auctions_core/src/Form/BiddersForm.php

modules/auctions_core/src/Form/BiddersForm.php
<?php

namespace Drupal\auctions_core\Form;

use Drupal\auctions_core\AuctionToolsTrait;
use Drupal\auctions_core\Entity\AuctionAutobidInterface;
use Drupal\auctions_core\Entity\AuctionItem;
use Drupal\auctions_core\Plugin\Validation\Constraint\CurbBids;
use Drupal\auctions_core\Service\AuctionTools;
use Drupal\Component\Utility\Html;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Datetime\DateFormatter;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class HelloForm.
 */
class BiddersForm extends FormBase {

  use AuctionToolsTrait;

  /**
   * Drupal\Core\Messenger\MessengerInterface definition.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The current user account.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;
  /**
   * Entity Type Manager.
   *
   * @var Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * AuctionTools.
   *
   * @var Drupal\auctions_core\Service\AuctionTools
   */
  protected $auctionTools;

  /**
   * Core module handler.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  public $configFactory;

  /**
   * The Date Fromatter.
   *
   * @var Drupal\Core\Datetime\DateFormatter
   */
  protected $dateFormatter;

  /**
   * Constructs a new BiddersForm object.
   *
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   Messenger Factory.
   * @param Drupal\Core\Session\AccountInterface $currentUser
   *   Account Interface.
   * @param Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   Entity Type Manager.
   * @param \Drupal\auctions_core\Service\AuctionTools $auctionTools
   *   AuctionTools service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   Configuration Factory.
   * @param Drupal\Core\Datetime\DateFormatter $dateFormatter
   *   Date Formatter.
   */
  public function __construct(MessengerInterface $messenger, AccountInterface $currentUser, EntityTypeManagerInterface $entityTypeManager, AuctionTools $auctionTools, ConfigFactoryInterface $configFactory, DateFormatter $dateFormatter) {
    $this->messenger = $messenger;
    $this->currentUser = $currentUser;
    $this->entityTypeManager = $entityTypeManager;
    $this->auctionTools = $auctionTools;
    $this->configFactory = $configFactory;
    $this->dateFormatter = $dateFormatter;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('messenger'),
      $container->get('current_user'),
      $container->get('entity_type.manager'),
      $container->get('auctions_core.tools'),
      $container->get('config.factory'),
      $container->get('date.formatter')
    );
  }

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

  /**
   * {@inheritdoc}
   *
   * $method='dialog'.  Preliminary ability to use HTML Dialogs with Bidders Form.
   */
  public function buildForm(array $form, FormStateInterface $form_state, $auctionItem = NULL, $method = NULL) {

    $auctionConf = $this->configFactory()->getEditable('auctions.item_settings');
    $dollar = $auctionConf->get('dollar-symbol');
    $thous = $auctionConf->get('thousand-separator');
    $dec = $auctionConf->get('decimal-separator');
    $item = (!empty($auctionItem[0])&& ($auctionItem[0] instanceof AuctionItem)) ? $auctionItem[0] : FALSE;

    // Set form for HTML Dialog uses.
    if ($method == 'dialog') {
      $form['#attributes']['method'] = 'dialog';
    }

    $form['#attributes']['id'] = Html::getUniqueId(Html::cleanCssIdentifier($this->getFormId() . '-item-' . $item->getId()));
    $form['#attributes']['data-auction-item'] = $item->getId();

    $currency = '<small>' . $item->getCurrencyCode() . '</small>';
    if ($item) {
      // Send only id, refresh data.
      $form_state->setFormState([
        'auction_item_id' => $item->getId(),
      ]);

      $hasBuyNow = $item->hasBuyNow();
      $instantOnly = $item->getInstantOnly();
        $form['#attributes']['class'][] = 'instant-mode-'. ( $instantOnly  ? 'enabled':'disabled');

      $canBid = $this->currentUser->hasPermission('add auction bids entities');
      if (!$canBid) {
        $form['permission-denied'] = [
          '#type' => 'inline_template',
          '#template' => '<p>{{ message }}</p>',
          '#context' => [
            'message' => $this->t('You are not able to bid at this time'),
          ],
        ];
      }
      elseif ($this->currentUser->isAnonymous()) {

        $destinationUrl = Url::fromRoute('<current>');
        $loginLink = Link::createFromRoute($this->t('Login'), 'user.login', [], ['query' => ['destination' => $destinationUrl->toString()]])->toString();
        $form['is-anon'] = [
          '#type' => 'inline_template',
          '#template' => '<p>{{ message }}</p><ul><li>{{ login }}</li><li>{{ register }}</li></ul>',
          '#context' => [
            'message' => $this->t('Please log in to bid'),
            'login' => $loginLink,
            'register' => Link::createFromRoute($this->t('Register'), 'user.register')->toString(),
          ],
        ];

      }
      else {
        if ($item->isClosed()) {
          $form['#attributes']['class'][] = 'auction-item-closed';
          $form['aution-closed'] = [
            '#type' => 'item',
            '#description' => $this->t('Auction is Closed.'),
          ];
        }
        elseif ($item->isOpen()) {
          $currentHightest = $item->seekCurrentHightest();
          $minPrice = $currentHightest['minPrice'];
          $selfBid = ($currentHightest['leadBid'] && $currentHightest['leadBid']->getOwnerId() == $this->currentUser->id()) ? TRUE : FALSE;

          $form['header'] = [
            '#type' => 'container',
            '#prefix' => '<header>',
            '#suffix' => '</header>',
            '#access' => !$instantOnly,
            '#attributes' => ['class' => ['bid-refresh-wrapper']],
          ];
          $form['header']['current'] = [
            '#type' => 'markup',
            '#markup' => '<dl><dt>' . $this->t('Current Offer: ') . '</dt><dd><span class="currency-symbol">' . $dollar . '</span><span class="current-formatted" data-auction-item="' . $item->id() . '">' . $this->showAsCents($minPrice, $dec, $thous) . '</span> <span class="currency-abbr">' . $currency . '</span></dd></dl>',
          ];

          // Phrasing our Rate for such small timeframe.
          $refreshRate = $auctionConf->get('ajax-rate');
          $ratePhrase = $this->t('@rate seconds', ['@rate' => $refreshRate]);
          if ($refreshRate == 60) {
            $ratePhrase = $this->t('1 Minute');
          }
          elseif ($refreshRate == 1) {
            $ratePhrase = $this->t('1 Second');
          }
          elseif ($refreshRate < 1) {
            $ratePhrase = $this->t('@rate second', ['@rate' => $refreshRate]);
          }

          $dates = $item->getDateStatus();
          $form['header']['bid-refresh'] = [
            '#access' => $auctionConf->get('ajax-refresh') === 1 ? TRUE : FALSE,
            '#theme' => 'auction_bid_refresh',
            '#id' => $item->getId(),
            '#rate' => $auctionConf->get('ajax-rate'),
            '#adrenaline' => $auctionConf->get('refresh-adrenaline'),
            '#until' => $dates['date_formatted']['end_unix'],
            '#rate_phrase' => $this->t('Refresh Rate:  @rate', ['@rate' => $ratePhrase]),
            '#preactivate' => $auctionConf->get('ajax-preactivate') === 1 ? 'true' : 'false',
          ];
          $form['header']['status'] = [
            '#type' => 'container',
            '#attributes' => ['class' => ['bid-status-wrapper']],
          ];

          $selfMessage = '';
          if ($selfBid) {
            $selfMessage = $this->selfBidPhrase();
            $form['header']['status']['self-bid'] = [
              '#type' => 'markup',
              '#markup' => '<span>' . $selfMessage . '</span>',
            ];
          }
          $form['#attached']['drupalSettings']['auctionsCoreBiddersForm'] = [
            'selfBid' => $selfMessage,
          ];

          $hasAutobid = $this->auctionTools->seekAutobid(
              $this->currentUser->id(),
              $item->id(),
              $item->getRelistCount()
            );

          // Audobids section.
          $currentAutobid = FALSE;
          $automaxTitle = $this->t('Your autobid maximum');
          $autoBidOptInTitle = $this->t('Autobidding Opt-in.');

          if ($hasAutobid instanceof AuctionAutobidInterface) {
            if ($hasAutobid->getAmountMax() > $item->seekCurrentHightest()['minPrice']) {
              $currentAutobid = $hasAutobid;
              $automaxTitle = $this->t('Adjust your autobid maximum');
            }
            else {
              $currentAutobid = FALSE;
              $autoBidOptInTitle = $this->t('Your autoBid has been outbidded. re-Autobidding Opt-in.');
            }
          }

          $showAutobidding = !$instantOnly &&  $auctionConf->get('autobid-mode') == 1;
          $form['autobid'] = [
            '#type' => 'details',
            '#open' => $currentAutobid,
            '#access' => $this->currentUser->hasPermission('add auction autobid entities') && $showAutobidding,
            '#title' => $this->t('Auto Bidding'),
            '#attributes' => [
              'class' => [
                'autobid-wrapper',
              ],
            ],
          ];

          $amountMax = $currentAutobid ? $currentAutobid->getAmountMax() : ($minPrice + $item->getBidStep());
          $form['autobid']['last-bidder'] = [
            '#type' => 'item',
            '#access' => $currentAutobid ? TRUE : FALSE,
            '#markup' => $this->t('Your current maximum:'),
            '#description' => $dollar . $this->showAsCents($amountMax, $dec, $thous) . ' ' . $currency,
          ];

          $form['autobid']['autobid_opt'] = [
            '#type' => 'checkbox',
            '#title' => $autoBidOptInTitle,
            '#access' => !$currentAutobid ,
            '#default_value' => $currentAutobid ? 1 : 0,
            '#states' => [
              'invisible' => [
                ':input[name*="autobid_opt"]' => ['checked' => TRUE],
              ],
            ],
          ];
          $form['autobid']['amount_max'] = [
            '#type' => 'number',
            '#field_prefix' => $dollar,
            '#title' => $automaxTitle,
            '#description' => $this->t("This item's Bid Step is @dollar@bidStep:", [
              '@dollar' => $dollar,
              '@bidStep' => $auctionItem[0]->getBidStep(),
            ]),
            '#step' => 'any',
            '#min' => $minPrice + ($item->getBidStep() * 2),
            '#states' => [
              'invisible' => [
                ':input[name*="autobid_opt"]' => ['checked' => FALSE],
              ],
                /* Reminder:  can't make required or browser validation will loop if opt-out btn is used. */
            ],
          ];
          if ($currentAutobid) {
            $form['autobid']['amount_max']['#access'] = FALSE;
          }

          $form['autobid']['opt_out'] = [
            '#type' => 'submit',
            '#name' => 'opt-out',
            '#access' => isset($currentAutobid) && $currentAutobid ? TRUE : FALSE,
            '#submit' => ['::optOutSubmit'],
            '#limit_validation_errors' => [],
            '#value' => $this->t('Remove my Auto Bidding'),
            '#attributes' => [
              'title' => $this->t("'Opt Out' without placing a bid."),
              'alt' => $this->t("Click here to 'opt out' of Auto Bidding without placing a bid."),
            ],
            '#states' => [
              'invisible' => [
                ':input[name*="autobid_opt"]' => ['checked' => FALSE],
              ],
            ],
          ];

          $form['bids'] = [
            '#type' => 'container',
            '#access' => !$instantOnly,
            '#attributes' => ['class' => ['standard-bid', 'clearfix']],
          ];

          $form['bids']['amount'] = [
            '#type' => 'number',
            '#field_prefix' => $dollar,
            '#required' => TRUE,
            '#field_suffix' => $currency,
            '#title' => $this->t('Your Bid'),
            '#title_display' => 'invisible',
            '#min' => ($minPrice + .01),
            '#size' => 12,
            '#step' => 'any',
          ];
          $default = $minPrice + $item->getBidStep();
          $form['bids']['amount']['#default_value'] = $default;
          $form['bids']['amount']['#attributes']['data-refresh'] = $minPrice;

          // Bid Refresh, items need always be output.
          if ($selfBid) {
           // $form['bids']['amount']['#disabled'] = 'disabled';
          }

          $form['bids']['submit'] = [
            '#type' => 'submit',
            '#name' => 'submit',
            '#value' => $this->t('Place your bid'),
          ];

          // Instant Bid section.
          $bidThreshold = $item->seekBidThreshold();
          $form['instant'] = [
            '#type' => $instantOnly ? 'fieldset' : 'details',
            '#open' => $instantOnly,
            '#title' => $this->t('Instant Buy'),
                 /*   todo: format from conf  . */
            '#markup' => $dollar . $this->showAsCents($item->getPriceBuyNow(), $dec, $thous) . ' ' . $currency,
            '#access' => ($instantOnly || $hasBuyNow) && !$bidThreshold,
            '#attributes' => [
              'class' => [
                'instant-bid',
              ],
            ],
          ];
          $form['instant']['buy_now_verify'] = [
            '#type' => 'checkbox',
            '#title' => $this->t("Yes, I'ld like to Buy Now"),
          ];
          $form['instant']['buy_now'] = [
            '#type' => 'submit',
            '#name' => 'buy-now',
            '#submit' => ['::buyNowSubmit'],
            '#validate' => ['::buyNowValidate'],
            '#value' => $this->t('Buy Now!'),
            '#states' => [
              'invisible' => [
                ':input[name*="buy_now_verify"]' => ['checked' => FALSE],
              ],
            ],
          ];

        }
        else {
          $form['auction-open'] = [
            '#type' => 'item',
            '#description' => $this->t('Bidding is not yet Open.'),
          ];
        }
      }

    }
    $form['#attached']['library'][] = 'auctions_core/bidders';
    $form['#cache']['max-age'] = 0;
    return $form;
  }

  /**
   * Form validation handler for the Buy Now submission.
   *
   * This method checks if the Buy Now submission is valid and
   * displays errors if any validation checks fail.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function buyNowValidate(array &$form, FormStateInterface $form_state) {
    $curbBids = new CurbBids();
    $itemId = $form_state->get('auction_item_id');
    $item = \Drupal::entityTypeManager()->getStorage('auction_item')->load($itemId);
    if ($item->isClosed()) {
      $form_state->setErrorByName('instant-price', $curbBids->auctionHasClosed);
    }
    $verify = $form_state->getValues()['buy_now_verify'];
    if ($verify == 0) {
      $form_state->setErrorByName('buy_now_verify', $this->t('You must pre-verify <q>Buy Now</q> submission.'));
    }
  }

  /**
   * Form submission handler for opting out of Auto Bidding.
   *
   * This method handles the form submission when a user chooses to opt out of
   * Auto Bidding for a specific auction item.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function optOutSubmit(array &$form, FormStateInterface $form_state) {
    $itemId = $form_state->get('auction_item_id');
    $item = \Drupal::entityTypeManager()->getStorage('auction_item')->load($itemId);
    $this->auctionTools->removeAutobid($this->currentUser->id(), $itemId, $item->getRelistCount());
  }

  /**
   * {@inheritdoc}
   */
  public function buyNowSubmit(array &$form, FormStateInterface $form_state) {
    $itemId = $form_state->get('auction_item_id');
    $item = \Drupal::entityTypeManager()->getStorage('auction_item')->load($itemId);

    $bid = $this->auctionTools->handleBid(
      $this->currentUser->id(),
      $item,
      $item->getPriceBuyNow(),
      FALSE,
      TRUE
    );

    if ($bid->id()) {
      $this->messenger()->addMessage($this->t('Congratulations! You have placed an Instant Buy! $%price.', [
        '%price' => $this->showAsCents($item->getPriceBuyNow(), '.', ','),
      ]));
    }
    else {
      $this->messenger()->addError($this->t('Something went wrong, please contact an Administrator.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $triggerBtn = $form_state->getTriggeringElement();
    if ($triggerBtn !== NULL && isset($triggerBtn['#name']) && $triggerBtn['#name'] == 'submit') {
      $curbBids = new CurbBids();
      $itemId = $form_state->get('auction_item_id');
      $item = \Drupal::entityTypeManager()->getStorage('auction_item')->load($itemId);
      $itemRelist = $item->getRelistCount();
      $currentBids = $item->getBids($itemRelist, 3);
      $processBids = $item->summarizeBids($currentBids);
      $amount = \floatval($form_state->getValue('amount'));
      if (!empty($processBids[0]) && $processBids[0]['uid'] == $this->currentUser->id()) {
        // Since this is the heaviest rule:  check for it first.
        $form_state->setErrorByName('amount', $curbBids->lastBidIsYours);
      }

      $itemPriceStarting = $item->getPriceStarting();
      $itemWorkflow = $item->getWorkflow();
      // Check if the value is an number.
      if ($itemWorkflow == 3 || $itemWorkflow == 4) {
        $form_state->setErrorByName('amount', $curbBids->auctionFinished);

      }
      if ($itemWorkflow == 0) {
        $form_state->setErrorByName('amount', $curbBids->auctionNew);
      }

      // If is past end time.  @page load vs submit post.
      $now = new DrupalDateTime('now');
      $auctionDates = $item->getDate();
      $getUserTimezone = date_default_timezone_get();
      $userTimezone = new \DateTimeZone($getUserTimezone);
      $auctionEnds = DrupalDateTime::createFromFormat('Y-m-d\TH:i:s', $auctionDates['end'], $this->auctionDefaultTimeZone())->setTimezone($userTimezone)->format('U');
      if ($now->format('U') > $auctionEnds) {
        $auctionEndDateTime = $auctionDates['end'];
        $endDate = DrupalDateTime::createFromFormat('Y-m-d\TH:i:s', $auctionEndDateTime, $this->auctionDefaultTimeZone())
          ->setTimezone($userTimezone)
          ->format('Y-m-d H:i:s');
        $form_state->setErrorByName('amount', str_replace('%endDate', $endDate, $curbBids->auctionHasExpired));
      }
      // If isn't higher than last/threshold.
      $highestCurrent = $item->seekCurrentHightest();
      if ((!empty($processBids[0]) && $amount < $processBids[0]['amount'])
          ||
        (!($amount > ($highestCurrent['minPrice'])))
      ) {
        $form_state->setErrorByName('amount', $curbBids->higherThanLastBid);
      }

      // Autobid.
      $hasAutobid = $this->auctionTools->seekAutobid($this->currentUser->id(), $item->id(), $itemRelist);
      $currentAutobid = FALSE;
      if ($hasAutobid instanceof AuctionAutobidInterface) {
        $currentAutobid = $hasAutobid;
      }

      $autobidOpt = $form_state->getValue('autobid_opt');
      // Reminder:  all form buttons should have unique #name.
      $triggerBtn = $form_state->getTriggeringElement()['#name'];
      $amountMax = $this->roundCents((float) $form_state->getValue('amount_max'));
      if ($triggerBtn != 'opt-out'
        && $autobidOpt == 1
        && ($currentAutobid && $amountMax != 0)
        && $amountMax < $highestCurrent['minPrice']
      ) {
        $form_state->setErrorByName('amount_max', $this->t('Your Max autobid has to be higher than current highest bid. Try a higher amount or click <q>Opt Out</q> .'));
      }
      parent::validateForm($form, $form_state);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $itemId = $form_state->get('auction_item_id');
    $item = \Drupal::entityTypeManager()->getStorage('auction_item')->load($itemId);
    $autobidOpt = $form_state->getValue('autobid_opt');
    // Reminder:  all form buttons should have unique #name.
    $amountMax = \floatval($form_state->getValue('amount_max'));
    if ($autobidOpt == 1 && $amountMax != 0) {
      // Process autobid.
      $this->auctionTools->handleAutobid(
        $this->currentUser->id(),
        $item->id(),
        $item->getRelistCount(),
        $amountMax
      );
    }

    $amount = \floatval($form_state->getValue('amount'));
    $bid = $this->auctionTools->handleBid(
      $this->currentUser->id(),
      $item,
      $amount
    );

    if ($bid->id()) {
      $this->messenger()->addMessage($this->t('Congratulations! You have placed your bid! $%price.', [
        '%price' => $this->showAsCents($amount, '.', ','),
      ]));
    }
    else {
      $this->messenger()->addError($this->t('Bidding failed.'));
    }
  }

}

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

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