You are here

public static function Price::processElement in Commerce Core 8.2

Builds the commerce_price form element.

Parameters

array $element: The initial commerce_price form element.

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form.

array $complete_form: The complete form structure.

Return value

array The built commerce_price form element.

Throws

\InvalidArgumentException Thrown when #default_value is not an instance of \Drupal\commerce_price\Price.

File

modules/price/src/Element/Price.php, line 80

Class

Price
Provides a price form element.

Namespace

Drupal\commerce_price\Element

Code

public static function processElement(array $element, FormStateInterface $form_state, array &$complete_form) {
  $default_value = $element['#default_value'];
  if (isset($default_value) && !self::validateDefaultValue($default_value)) {
    throw new \InvalidArgumentException('The #default_value for a commerce_price element must be an array with "number" and "currency_code" keys.');
  }

  /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $currency_storage */
  $currency_storage = \Drupal::service('entity_type.manager')
    ->getStorage('commerce_currency');

  /** @var \Drupal\commerce_price\Entity\CurrencyInterface[] $currencies */
  $currencies = $currency_storage
    ->loadMultiple();
  $currency_codes = array_keys($currencies);

  // Keep only available currencies.
  $available_currencies = $element['#available_currencies'];
  if (isset($available_currencies) && !empty($available_currencies)) {
    $currency_codes = array_intersect($currency_codes, $available_currencies);
  }

  // Stop rendering if there are no currencies available.
  if (empty($currency_codes)) {
    return $element;
  }
  $fraction_digits = [];
  foreach ($currencies as $currency) {
    $fraction_digits[] = $currency
      ->getFractionDigits();
  }
  $element['#tree'] = TRUE;
  $element['#attributes']['class'][] = 'form-type-commerce-price';

  // Provide an example to the end user so that they know which decimal
  // separator to use. This is the same pattern Drupal core uses.
  $number_formatter = \Drupal::service('commerce_price.number_formatter');
  $element['number'] = [
    '#type' => 'commerce_number',
    '#title' => $element['#title'],
    '#title_display' => $element['#title_display'],
    '#default_value' => $default_value ? $default_value['number'] : NULL,
    '#required' => $element['#required'],
    '#size' => $element['#size'],
    '#maxlength' => $element['#maxlength'],
    '#min_fraction_digits' => min($fraction_digits),
    '#min' => $element['#allow_negative'] ? NULL : 0,
    '#error_no_message' => TRUE,
    '#description' => t('Format: @format', [
      '@format' => $number_formatter
        ->format('9.99'),
    ]),
  ];
  if (isset($element['#ajax'])) {
    $element['number']['#ajax'] = $element['#ajax'];
  }
  if (count($currency_codes) == 1) {
    $last_visible_element = 'number';
    $currency_code = reset($currency_codes);
    $element['number']['#field_suffix'] = $currency_code;
    $element['currency_code'] = [
      '#type' => 'hidden',
      '#value' => $currency_code,
    ];
  }
  else {
    $last_visible_element = 'currency_code';
    $element['currency_code'] = [
      '#type' => 'select',
      '#title' => t('Currency'),
      '#default_value' => $default_value ? $default_value['currency_code'] : NULL,
      '#options' => array_combine($currency_codes, $currency_codes),
      '#title_display' => 'invisible',
      '#field_suffix' => '',
    ];
    if (isset($element['#ajax'])) {
      $element['currency_code']['#ajax'] = $element['#ajax'];
    }
  }

  // Add the help text if specified.
  if (!empty($element['#description'])) {
    $element[$last_visible_element]['#description'] = $element['#description'];
  }

  // Remove the keys that were transferred to child elements.
  unset($element['#size']);
  unset($element['#maxlength']);
  unset($element['#ajax']);
  unset($element['#description']);
  return $element;
}