You are here

abstract class PaymentGatewayBase in Commerce Core 8.2

Provides the base class for payment gateways.

Hierarchy

Expanded class hierarchy of PaymentGatewayBase

File

modules/payment/src/Plugin/Commerce/PaymentGateway/PaymentGatewayBase.php, line 27

Namespace

Drupal\commerce_payment\Plugin\Commerce\PaymentGateway
View source
abstract class PaymentGatewayBase extends PluginBase implements PaymentGatewayInterface, ContainerFactoryPluginInterface {
  use PluginWithFormsTrait;

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

  /**
   * The parent config entity.
   *
   * Not available while the plugin is being configured.
   *
   * @var \Drupal\commerce_payment\Entity\PaymentGatewayInterface
   */
  protected $parentEntity;

  /**
   * The ID of the parent config entity.
   *
   * @deprecated in commerce:8.x-2.16 and is removed from commerce:3.x.
   *   Use $this->parentEntity->id() instead.
   *
   * @var string
   */
  protected $entityId;

  /**
   * The payment type used by the gateway.
   *
   * @var \Drupal\commerce_payment\Plugin\Commerce\PaymentType\PaymentTypeInterface
   */
  protected $paymentType;

  /**
   * The payment method types handled by the gateway.
   *
   * @var \Drupal\commerce_payment\Plugin\Commerce\PaymentMethodType\PaymentMethodTypeInterface[]
   */
  protected $paymentMethodTypes;

  /**
   * The time.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The minor units converter.
   *
   * @var \Drupal\commerce_price\MinorUnitsConverterInterface
   */
  protected $minorUnitsConverter;

  /**
   * Constructs a new PaymentGatewayBase 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.
   * @param \Drupal\commerce_payment\PaymentTypeManager $payment_type_manager
   *   The payment type manager.
   * @param \Drupal\commerce_payment\PaymentMethodTypeManager $payment_method_type_manager
   *   The payment method type manager.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time.
   * @param \Drupal\commerce_price\MinorUnitsConverterInterface $minor_units_converter
   *   The minor units converter.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, MinorUnitsConverterInterface $minor_units_converter = NULL) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entity_type_manager;
    $this->time = $time;
    if (!$minor_units_converter instanceof MinorUnitsConverterInterface) {
      @trigger_error('Calling PaymentGatewayBase::__construct() with the $minor_units_converter argument is supported in commerce:2.25 and will be required before commerce:3.0. See https://www.drupal.org/project/commerce/issues/3150917.', E_USER_DEPRECATED);
      $minor_units_converter = \Drupal::service('commerce_price.minor_units_converter');
    }
    $this->minorUnitsConverter = $minor_units_converter;
    if (array_key_exists('_entity', $configuration)) {
      $this->parentEntity = $configuration['_entity'];
      $this->entityId = $this->parentEntity
        ->id();
      unset($configuration['_entity']);
    }

    // Instantiate the types right away to ensure that their IDs are valid.
    $this->paymentType = $payment_type_manager
      ->createInstance($this->pluginDefinition['payment_type']);
    foreach ($this->pluginDefinition['payment_method_types'] as $plugin_id) {
      $this->paymentMethodTypes[$plugin_id] = $payment_method_type_manager
        ->createInstance($plugin_id);
    }
    $this->pluginDefinition['forms'] += $this
      ->getDefaultForms();
    $this
      ->setConfiguration($configuration);
  }

  /**
   * {@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'), $container
      ->get('plugin.manager.commerce_payment_type'), $container
      ->get('plugin.manager.commerce_payment_method_type'), $container
      ->get('datetime.time'), $container
      ->get('commerce_price.minor_units_converter'));
  }

  /**
   * {@inheritdoc}
   */
  public function __sleep() {
    if (!empty($this->parentEntity)) {
      $this->_parentEntityId = $this->parentEntity
        ->id();
      unset($this->parentEntity);
    }
    return parent::__sleep();
  }

  /**
   * {@inheritdoc}
   */
  public function __wakeup() {
    parent::__wakeup();
    if (!empty($this->_parentEntityId)) {
      $payment_gateway_storage = $this->entityTypeManager
        ->getStorage('commerce_payment_gateway');
      $this->parentEntity = $payment_gateway_storage
        ->load($this->_parentEntityId);
      unset($this->_parentEntityId);
    }
  }

  /**
   * Gets the default payment gateway forms.
   *
   * @return array
   *   A list of plugin form classes keyed by operation.
   */
  protected function getDefaultForms() {
    $default_forms = [];
    if ($this instanceof SupportsStoredPaymentMethodsInterface) {
      $default_forms['add-payment-method'] = 'Drupal\\commerce_payment\\PluginForm\\PaymentMethodAddForm';
    }
    if ($this instanceof SupportsUpdatingStoredPaymentMethodsInterface) {
      $default_forms['edit-payment-method'] = 'Drupal\\commerce_payment\\PluginForm\\PaymentMethodEditForm';
    }
    if ($this instanceof SupportsAuthorizationsInterface) {
      $default_forms['capture-payment'] = 'Drupal\\commerce_payment\\PluginForm\\PaymentCaptureForm';
    }
    if ($this instanceof SupportsVoidsInterface) {
      $default_forms['void-payment'] = 'Drupal\\commerce_payment\\PluginForm\\PaymentVoidForm';
    }
    if ($this instanceof SupportsRefundsInterface) {
      $default_forms['refund-payment'] = 'Drupal\\commerce_payment\\PluginForm\\PaymentRefundForm';
    }
    return $default_forms;
  }

  /**
   * {@inheritdoc}
   */
  public function getLabel() {
    return $this->pluginDefinition['label'];
  }

  /**
   * {@inheritdoc}
   */
  public function getDisplayLabel() {
    return $this->configuration['display_label'];
  }

  /**
   * {@inheritdoc}
   */
  public function getMode() {
    return $this->configuration['mode'];
  }

  /**
   * {@inheritdoc}
   */
  public function getSupportedModes() {
    return $this->pluginDefinition['modes'];
  }

  /**
   * {@inheritdoc}
   */
  public function getJsLibrary() {
    $js_library = NULL;
    if (!empty($this->pluginDefinition['js_library'])) {
      $js_library = $this->pluginDefinition['js_library'];
    }
    return $js_library;
  }

  /**
   * {@inheritdoc}
   */
  public function getPaymentType() {
    return $this->paymentType;
  }

  /**
   * {@inheritdoc}
   */
  public function getPaymentMethodTypes() {

    // Filter out payment method types disabled by the merchant.
    return array_intersect_key($this->paymentMethodTypes, array_flip($this->configuration['payment_method_types']));
  }

  /**
   * {@inheritdoc}
   */
  public function getDefaultPaymentMethodType() {
    $default_payment_method_type = $this->pluginDefinition['default_payment_method_type'];
    if (!isset($this->paymentMethodTypes[$default_payment_method_type])) {
      throw new \InvalidArgumentException('Invalid default_payment_method_type specified.');
    }
    return $this->paymentMethodTypes[$default_payment_method_type];
  }

  /**
   * {@inheritdoc}
   */
  public function getCreditCardTypes() {

    // @todo Allow the list to be restricted by the merchant.
    return array_intersect_key(CreditCard::getTypes(), array_flip($this->pluginDefinition['credit_card_types']));
  }

  /**
   * {@inheritdoc}
   */
  public function collectsBillingInformation() {
    return $this->configuration['collect_billing_information'];
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    return [];
  }

  /**
   * {@inheritdoc}
   */
  public function getConfiguration() {
    return $this->configuration;
  }

  /**
   * {@inheritdoc}
   */
  public function setConfiguration(array $configuration) {
    $this->configuration = NestedArray::mergeDeep($this
      ->defaultConfiguration(), $configuration);

    // Providing a default for payment_metod_types in defaultConfiguration()
    // doesn't work because NestedArray::mergeDeep causes duplicates.
    if (empty($this->configuration['payment_method_types'])) {
      $this->configuration['payment_method_types'][] = 'credit_card';
    }
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $modes = array_keys($this
      ->getSupportedModes());
    return [
      'display_label' => $this->pluginDefinition['display_label'],
      'mode' => $modes ? reset($modes) : '',
      'payment_method_types' => [],
      'collect_billing_information' => TRUE,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $modes = $this
      ->getSupportedModes();
    $payment_method_types = array_map(function ($payment_method_type) {
      return $payment_method_type
        ->getLabel();
    }, $this->paymentMethodTypes);
    $form['display_label'] = [
      '#type' => 'textfield',
      '#title' => $this
        ->t('Display name'),
      '#description' => $this
        ->t('Shown to customers during checkout.'),
      '#default_value' => $this->configuration['display_label'],
      '#required' => TRUE,
    ];
    if (count($modes) > 1) {
      $form['mode'] = [
        '#type' => 'radios',
        '#title' => $this
          ->t('Mode'),
        '#options' => $modes,
        '#default_value' => $this->configuration['mode'],
        '#required' => TRUE,
      ];
    }
    else {
      $mode_names = array_keys($modes);
      $form['mode'] = [
        '#type' => 'value',
        '#value' => reset($mode_names),
      ];
    }
    if (count($payment_method_types) > 1) {
      $form['payment_method_types'] = [
        '#type' => 'checkboxes',
        '#title' => $this
          ->t('Payment method types'),
        '#options' => $payment_method_types,
        '#default_value' => $this->configuration['payment_method_types'],
        '#required' => TRUE,
      ];
    }
    else {
      $form['payment_method_types'] = [
        '#type' => 'value',
        '#value' => $payment_method_types,
      ];
    }
    $form['collect_billing_information'] = [
      '#type' => 'checkbox',
      '#title' => $this
        ->t('Collect billing information'),
      '#description' => $this
        ->t('Before disabling, make sure you are not legally required to collect billing information.'),
      '#default_value' => $this->configuration['collect_billing_information'],
      // Merchants can disable collecting billing information only if the
      // payment gateway indicated that it doesn't require it.
      '#access' => !$this->pluginDefinition['requires_billing_information'],
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    if (!$form_state
      ->getErrors()) {
      $values = $form_state
        ->getValue($form['#parents']);
      $values['payment_method_types'] = array_filter($values['payment_method_types']);
      $this->configuration = [];
      $this->configuration['display_label'] = $values['display_label'];
      $this->configuration['mode'] = $values['mode'];
      $this->configuration['payment_method_types'] = array_keys($values['payment_method_types']);
      $this->configuration['collect_billing_information'] = $values['collect_billing_information'];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function buildPaymentOperations(PaymentInterface $payment) {
    $operations = [];
    if ($this instanceof SupportsAuthorizationsInterface) {
      $operations['capture'] = [
        'title' => $this
          ->t('Capture'),
        'page_title' => $this
          ->t('Capture payment'),
        'plugin_form' => 'capture-payment',
        'access' => $this
          ->canCapturePayment($payment),
      ];
    }
    if ($this instanceof SupportsVoidsInterface) {
      $operations['void'] = [
        'title' => $this
          ->t('Void'),
        'page_title' => $this
          ->t('Void payment'),
        'plugin_form' => 'void-payment',
        'access' => $this
          ->canVoidPayment($payment),
      ];
    }
    if ($this instanceof SupportsRefundsInterface) {
      $operations['refund'] = [
        'title' => $this
          ->t('Refund'),
        'page_title' => $this
          ->t('Refund payment'),
        'plugin_form' => 'refund-payment',
        'access' => $this
          ->canRefundPayment($payment),
      ];
    }
    return $operations;
  }

  /**
   * {@inheritdoc}
   */
  public function canCapturePayment(PaymentInterface $payment) {
    return $payment
      ->getState()
      ->getId() === 'authorization';
  }

  /**
   * {@inheritdoc}
   */
  public function canRefundPayment(PaymentInterface $payment) {
    return in_array($payment
      ->getState()
      ->getId(), [
      'completed',
      'partially_refunded',
    ], TRUE);
  }

  /**
   * {@inheritdoc}
   */
  public function canVoidPayment(PaymentInterface $payment) {
    return $payment
      ->getState()
      ->getId() === 'authorization';
  }

  /**
   * {@inheritdoc}
   */
  public function buildAvsResponseCodeLabel($avs_response_code, $card_type) {
    $avs_code_meanings = CreditCard::getAvsResponseCodeMeanings();
    if (!isset($avs_code_meanings[$card_type][$avs_response_code])) {
      return NULL;
    }
    return $avs_code_meanings[$card_type][$avs_response_code];
  }

  /**
   * {@inheritdoc}
   */
  public function toMinorUnits(Price $amount) {
    return $this->minorUnitsConverter
      ->toMinorUnits($amount);
  }

  /**
   * Gets the remote customer ID for the given user.
   *
   * The remote customer ID is specific to a payment gateway instance
   * in the configured mode. This allows the gateway to skip test customers
   * after the gateway has been switched to live mode.
   *
   * @param \Drupal\user\UserInterface $account
   *   The user account.
   *
   * @return string
   *   The remote customer ID, or NULL if none found.
   */
  protected function getRemoteCustomerId(UserInterface $account) {
    $remote_id = NULL;
    if ($account
      ->isAuthenticated()) {
      $provider = $this->parentEntity
        ->id() . '|' . $this
        ->getMode();

      /** @var \Drupal\commerce\Plugin\Field\FieldType\RemoteIdFieldItemListInterface $remote_ids */
      $remote_ids = $account
        ->get('commerce_remote_id');
      $remote_id = $remote_ids
        ->getByProvider($provider);

      // Gateways used to key customer IDs by module name, migrate that data.
      if (!$remote_id) {
        $remote_id = $remote_ids
          ->getByProvider($this->pluginDefinition['provider']);
        if ($remote_id) {
          $remote_ids
            ->setByProvider($this->pluginDefinition['provider'], NULL);
          $remote_ids
            ->setByProvider($provider, $remote_id);
          $account
            ->save();
        }
      }
    }
    return $remote_id;
  }

  /**
   * Sets the remote customer ID for the given user.
   *
   * @param \Drupal\user\UserInterface $account
   *   The user account.
   * @param string $remote_id
   *   The remote customer ID.
   */
  protected function setRemoteCustomerId(UserInterface $account, $remote_id) {
    if ($account
      ->isAuthenticated()) {

      /** @var \Drupal\commerce\Plugin\Field\FieldType\RemoteIdFieldItemListInterface $remote_ids */
      $remote_ids = $account
        ->get('commerce_remote_id');
      $remote_ids
        ->setByProvider($this->parentEntity
        ->id() . '|' . $this
        ->getMode(), $remote_id);
    }
  }

  /**
   * Asserts that the payment state matches one of the allowed states.
   *
   * @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
   *   The payment.
   * @param string[] $states
   *   The allowed states.
   *
   * @throws \InvalidArgumentException
   *   Thrown if the payment state does not match the allowed states.
   */
  protected function assertPaymentState(PaymentInterface $payment, array $states) {
    $state = $payment
      ->getState()
      ->getId();
    if (!in_array($state, $states)) {
      throw new \InvalidArgumentException(sprintf('The provided payment is in an invalid state ("%s").', $state));
    }
  }

  /**
   * Asserts that the payment method is neither empty nor expired.
   *
   * @param \Drupal\commerce_payment\Entity\PaymentMethodInterface $payment_method
   *   The payment method.
   *
   * @throws \InvalidArgumentException
   *   Thrown when the payment method is empty.
   * @throws \Drupal\commerce_payment\Exception\HardDeclineException
   *   Thrown when the payment method has expired.
   */
  protected function assertPaymentMethod(PaymentMethodInterface $payment_method = NULL) {
    if (empty($payment_method)) {
      throw new \InvalidArgumentException('The provided payment has no payment method referenced.');
    }
    if ($payment_method
      ->isExpired()) {
      throw new HardDeclineException('The provided payment method has expired');
    }
  }

  /**
   * Asserts that the refund amount is valid.
   *
   * @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
   *   The payment.
   * @param \Drupal\commerce_price\Price $refund_amount
   *   The refund amount.
   *
   * @throws \Drupal\commerce_payment\Exception\InvalidRequestException
   *   Thrown when the refund amount is larger than the payment balance.
   */
  protected function assertRefundAmount(PaymentInterface $payment, Price $refund_amount) {
    $balance = $payment
      ->getBalance();
    if ($refund_amount
      ->greaterThan($balance)) {
      throw new InvalidRequestException(sprintf("Can't refund more than %s.", $balance
        ->__toString()));
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
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.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PaymentGatewayBase::$entityId Deprecated protected property The ID of the parent config entity.
PaymentGatewayBase::$entityTypeManager protected property The entity type manager.
PaymentGatewayBase::$minorUnitsConverter protected property The minor units converter.
PaymentGatewayBase::$parentEntity protected property The parent config entity.
PaymentGatewayBase::$paymentMethodTypes protected property The payment method types handled by the gateway.
PaymentGatewayBase::$paymentType protected property The payment type used by the gateway.
PaymentGatewayBase::$time protected property The time.
PaymentGatewayBase::assertPaymentMethod protected function Asserts that the payment method is neither empty nor expired.
PaymentGatewayBase::assertPaymentState protected function Asserts that the payment state matches one of the allowed states.
PaymentGatewayBase::assertRefundAmount protected function Asserts that the refund amount is valid.
PaymentGatewayBase::buildAvsResponseCodeLabel public function Builds a label for the given AVS response code and card type. Overrides PaymentGatewayInterface::buildAvsResponseCodeLabel 2
PaymentGatewayBase::buildConfigurationForm public function Form constructor. Overrides PluginFormInterface::buildConfigurationForm 3
PaymentGatewayBase::buildPaymentOperations public function Builds the available operations for the given payment. Overrides PaymentGatewayInterface::buildPaymentOperations 1
PaymentGatewayBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies
PaymentGatewayBase::canCapturePayment public function
PaymentGatewayBase::canRefundPayment public function
PaymentGatewayBase::canVoidPayment public function
PaymentGatewayBase::collectsBillingInformation public function Gets whether the payment gateway collects billing information. Overrides PaymentGatewayInterface::collectsBillingInformation
PaymentGatewayBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 2
PaymentGatewayBase::defaultConfiguration public function Gets default configuration for this plugin. Overrides ConfigurableInterface::defaultConfiguration 3
PaymentGatewayBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
PaymentGatewayBase::getCreditCardTypes public function Gets the credit card types handled by the gateway. Overrides PaymentGatewayInterface::getCreditCardTypes
PaymentGatewayBase::getDefaultForms protected function Gets the default payment gateway forms. 1
PaymentGatewayBase::getDefaultPaymentMethodType public function Gets the default payment method type. Overrides PaymentGatewayInterface::getDefaultPaymentMethodType
PaymentGatewayBase::getDisplayLabel public function Gets the payment gateway display label. Overrides PaymentGatewayInterface::getDisplayLabel
PaymentGatewayBase::getJsLibrary public function Gets the JS library ID. Overrides PaymentGatewayInterface::getJsLibrary
PaymentGatewayBase::getLabel public function Gets the payment gateway label. Overrides PaymentGatewayInterface::getLabel
PaymentGatewayBase::getMode public function Gets the mode in which the payment gateway is operating. Overrides PaymentGatewayInterface::getMode
PaymentGatewayBase::getPaymentMethodTypes public function Gets the payment method types handled by the payment gateway. Overrides PaymentGatewayInterface::getPaymentMethodTypes
PaymentGatewayBase::getPaymentType public function Gets the payment type used by the payment gateway. Overrides PaymentGatewayInterface::getPaymentType
PaymentGatewayBase::getRemoteCustomerId protected function Gets the remote customer ID for the given user.
PaymentGatewayBase::getSupportedModes public function Gets the supported modes. Overrides PaymentGatewayInterface::getSupportedModes
PaymentGatewayBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
PaymentGatewayBase::setRemoteCustomerId protected function Sets the remote customer ID for the given user.
PaymentGatewayBase::submitConfigurationForm public function Form submission handler. Overrides PluginFormInterface::submitConfigurationForm 3
PaymentGatewayBase::toMinorUnits public function Converts the given amount to its minor units. Overrides PaymentGatewayInterface::toMinorUnits
PaymentGatewayBase::validateConfigurationForm public function Form validation handler. Overrides PluginFormInterface::validateConfigurationForm
PaymentGatewayBase::__construct public function Constructs a new PaymentGatewayBase object. Overrides PluginBase::__construct 3
PaymentGatewayBase::__sleep public function Overrides DependencySerializationTrait::__sleep
PaymentGatewayBase::__wakeup public function Overrides DependencySerializationTrait::__wakeup
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.
PluginWithFormsTrait::getFormClass public function
PluginWithFormsTrait::hasFormClass public function
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.