You are here

private function ProductBundleItemsWidget::getBundleItemForm in Commerce Product Bundle 8

Gets the child form element for a given bundle item.

Parameters

\Drupal\commerce_product_bundle\Entity\BundleItemInterface $bundle_item: The bundle item.

array $form: The complete form array.

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

array $parents: The parents of the bundle item form element in the form structure.

Return value

array A renderable form array for the given bundle item.

1 call to ProductBundleItemsWidget::getBundleItemForm()
ProductBundleItemsWidget::formElement in src/Plugin/Field/FieldWidget/ProductBundleItemsWidget.php
Returns the form for a single field widget.

File

src/Plugin/Field/FieldWidget/ProductBundleItemsWidget.php, line 132

Class

ProductBundleItemsWidget
Plugin implementation of the 'commerce_product_bundle_items' widget.

Namespace

Drupal\commerce_product_bundle\Plugin\Field\FieldWidget

Code

private function getBundleItemForm(BundleItemInterface $bundle_item, array &$form, FormStateInterface $form_state, array $parents) {
  $bundle_item_form = [
    'bundle_item' => [
      '#type' => 'value',
      '#value' => $bundle_item,
    ],
  ];

  /** @var \Drupal\commerce_product\Entity\ProductInterface $product */
  $product = $bundle_item
    ->getProduct();

  /** @var \Drupal\commerce_product\Entity\ProductVariationInterface[] $variations */
  $variations = $bundle_item
    ->getVariations();
  $min_qty = $bundle_item
    ->getMinimumQuantity();
  $max_qty = $bundle_item
    ->getMaximumQuantity();
  if ($min_qty === $max_qty) {
    $bundle_item_form['qty'] = [
      '#type' => 'value',
      '#value' => $bundle_item
        ->getQuantity(),
    ];
  }
  else {
    $bundle_item_form['qty'] = [
      '#type' => 'number',
      '#title' => $this
        ->t('Quantity'),
      '#min' => $min_qty,
      '#max' => $max_qty,
      '#default_value' => $min_qty,
      '#step' => 1,
    ];
  }
  if (count($variations) === 0) {

    // Nothing to purchase, tell the parent form to hide itself.
    $form_state
      ->set('hide_form', TRUE);
    $bundle_item_form['variation'] = [
      '#type' => 'value',
      '#value' => 0,
    ];
    return $bundle_item_form;
  }
  elseif (count($variations) === 1) {

    /** @var \Drupal\commerce_product\Entity\ProductVariationInterface $selected_variation */
    $selected_variation = reset($variations);

    // For regular products, from which this logic was adapted, the variation
    // form is only hidden (with simply this value stored) when the variation
    // has no attribute fields (to show the customer which variation they are
    // purchasing). But since the product bundle is expected to indicate the
    // items in the bundle, and to avoid unnecessary UI clutter, we hide all
    // attribute widgets when there is only one variation.
    // Compare this with ProductVariationAttributesWidget::formElement.
    $bundle_item_form['variation'] = [
      '#type' => 'value',
      '#value' => $selected_variation
        ->id(),
    ];
    $bundle_item
      ->setCurrentVariation($selected_variation);
    $bundle_item_form['title'] = [
      '#type' => 'markup',
      '#markup' => $bundle_item
        ->getTitle(),
      '#prefix' => '<p>',
      '#suffix' => '</p>',
    ];
    return $bundle_item_form;
  }

  // Build the bundle item's full attribute form.
  $wrapper_id = Html::getUniqueId('commerce-product-bundle-item-add-to-cart-form');
  $bundle_item_form += [
    '#wrapper_id' => $wrapper_id,
    '#prefix' => '<div id="' . $wrapper_id . '">',
    '#suffix' => '</div>',
  ];
  $user_input = (array) NestedArray::getValue($form_state
    ->getUserInput(), $parents);
  if (!empty($user_input)) {
    $selected_variation = $this
      ->selectVariationFromUserInput($variations, $user_input);
  }
  else {
    $selected_variation = $this->variationStorage
      ->loadFromContext($product);

    // The returned variation must also be enabled.
    if (!in_array($selected_variation, $variations)) {
      $selected_variation = reset($variations);
    }
  }
  $bundle_item_form['variation'] = [
    '#type' => 'value',
    '#value' => $selected_variation
      ->id(),
  ];
  $bundle_item
    ->setCurrentVariation($selected_variation);

  // Set the selected variation in the form state for our AJAX callback.
  $form_state
    ->set('purchased_entity][widget][0][bundle_items][' . $bundle_item
    ->id() . '][selected_variation', $selected_variation
    ->id());
  $bundle_item_form['attributes'] = [
    '#type' => 'container',
    '#attributes' => [
      'class' => [
        'attribute-widgets',
      ],
    ],
  ];
  foreach ($this
    ->getItemAttributeInfo($selected_variation, $variations) as $field_name => $attribute) {
    $bundle_item_form['attributes'][$field_name] = [
      '#type' => $attribute['element_type'],
      '#title' => $attribute['title'],
      '#options' => $attribute['values'],
      '#required' => $attribute['required'],
      '#default_value' => $selected_variation
        ->getAttributeValueId($field_name),
      '#ajax' => [
        'callback' => [
          get_class($this),
          'ajaxRefresh',
        ],
        'wrapper' => $bundle_item_form['#wrapper_id'],
      ],
    ];

    // Convert the _none option into #empty_value.
    if (isset($bundle_item_form['attributes'][$field_name]['#options']['_none'])) {
      if (!$bundle_item_form['attributes'][$field_name]['#required']) {
        $bundle_item_form['attributes'][$field_name]['#empty_value'] = '';
      }
      unset($bundle_item_form['attributes'][$field_name]['#options']['_none']);
    }

    // 1 required value -> Disable the bundle_item_variations to skip unneeded ajax calls.
    if ($attribute['required'] && count($attribute['values']) === 1) {
      $bundle_item_form['attributes'][$field_name]['#disabled'] = TRUE;
    }

    // Optimize the UX of optional attributes:
    // - Hide attributes that have no values.
    // - Require attributes that have a value on each variation.
    if (empty($bundle_item_form['attributes'][$field_name]['#options'])) {
      $bundle_item_form['attributes'][$field_name]['#access'] = FALSE;
    }
    if (!isset($bundle_item_form['attributes'][$field_name]['#empty_value'])) {
      $bundle_item_form['attributes'][$field_name]['#required'] = TRUE;
    }
  }
  return $bundle_item_form;
}