public function ShippingInformation::buildPaneForm in Commerce Shipping 8.2
Builds the pane form.
Parameters
array $pane_form: The pane form, containing the following basic properties:
- #parents: Identifies the position of the pane form in the overall parent form, and identifies the location where the field values are placed within $form_state->getValues().
\Drupal\Core\Form\FormStateInterface $form_state: The form state of the parent form.
array $complete_form: The complete form structure.
Overrides CheckoutPaneInterface::buildPaneForm
File
- src/
Plugin/ Commerce/ CheckoutPane/ ShippingInformation.php, line 214
Class
- ShippingInformation
- Provides the shipping information pane.
Namespace
Drupal\commerce_shipping\Plugin\Commerce\CheckoutPaneCode
public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
$store = $this->order
->getStore();
$available_countries = [];
foreach ($store
->get('shipping_countries') as $country_item) {
$available_countries[] = $country_item->value;
}
/** @var \Drupal\commerce\Plugin\Commerce\InlineForm\EntityInlineFormInterface $inline_form */
$inline_form = $this->inlineFormManager
->createInstance('customer_profile', [
'profile_scope' => 'shipping',
'available_countries' => $available_countries,
'address_book_uid' => $this->order
->getCustomerId(),
// Don't copy the profile to address book until the order is placed.
'copy_on_save' => FALSE,
], $this
->getShippingProfile());
// Prepare the form for ajax.
// Not using Html::getUniqueId() on the wrapper ID to avoid #2675688.
$pane_form['#wrapper_id'] = 'shipping-information-wrapper';
$pane_form['#prefix'] = '<div id="' . $pane_form['#wrapper_id'] . '">';
$pane_form['#suffix'] = '</div>';
// Auto recalculation is enabled only when a shipping profile is required.
$pane_form['#auto_recalculate'] = !empty($this->configuration['auto_recalculate']) && !empty($this->configuration['require_shipping_profile']);
$pane_form['#after_build'][] = [
static::class,
'autoRecalculateProcess',
];
$pane_form['shipping_profile'] = [
'#parents' => array_merge($pane_form['#parents'], [
'shipping_profile',
]),
'#inline_form' => $inline_form,
];
$pane_form['shipping_profile'] = $inline_form
->buildInlineForm($pane_form['shipping_profile'], $form_state);
$triggering_element = $form_state
->getTriggeringElement();
// The shipping_profile should always exist in form state (and not just
// after "Recalculate shipping" is clicked).
if (!$form_state
->has('shipping_profile') || isset($triggering_element['#parents']) && in_array('select_address', $triggering_element['#parents'])) {
$form_state
->set('shipping_profile', $inline_form
->getEntity());
}
$class = get_class($this);
// Ensure selecting a different address refreshes the entire form.
if (isset($pane_form['shipping_profile']['select_address'])) {
$pane_form['shipping_profile']['select_address']['#ajax'] = [
'callback' => [
$class,
'ajaxRefreshForm',
],
'element' => $pane_form['#parents'],
];
// Selecting a different address should trigger a recalculation.
$pane_form['shipping_profile']['select_address']['#recalculate'] = TRUE;
}
$pane_form['recalculate_shipping'] = [
'#type' => 'button',
'#value' => $this
->t('Recalculate shipping'),
'#recalculate' => TRUE,
'#ajax' => [
'callback' => [
$class,
'ajaxRefreshForm',
],
'element' => $pane_form['#parents'],
],
// The calculation process only needs a valid shipping profile.
'#limit_validation_errors' => [
array_merge($pane_form['#parents'], [
'shipping_profile',
]),
],
'#after_build' => [
[
static::class,
'clearValues',
],
],
];
$pane_form['removed_shipments'] = [
'#type' => 'value',
'#value' => [],
];
$pane_form['shipments'] = [
'#type' => 'container',
];
$shipping_profile = $form_state
->get('shipping_profile');
$shipments = $this->order
->get('shipments')
->referencedEntities();
$recalculate_shipping = $form_state
->get('recalculate_shipping');
$can_calculate_rates = $this
->canCalculateRates($shipping_profile);
// If the shipping recalculation is triggered, ensure the rates can
// be recalculated (i.e a valid address is entered).
if ($recalculate_shipping && !$can_calculate_rates) {
$recalculate_shipping = FALSE;
$shipments = [];
}
// Ensure the profile is saved with the latest address, it's necessary
// to do that in case the profile isn't new, otherwise the shipping profile
// referenced by the shipment won't reflect the updated address.
if (!$shipping_profile
->isNew() && $shipping_profile
->hasTranslationChanges() && $can_calculate_rates) {
$shipping_profile
->save();
$inline_form
->setEntity($shipping_profile);
}
$force_packing = empty($shipments) && $can_calculate_rates;
if ($recalculate_shipping || $force_packing) {
// We're still relying on the packer manager for packing the order since
// we don't want the shipments to be saved for performance reasons.
// The shipments are saved on pane submission.
list($shipments, $removed_shipments) = $this->packerManager
->packToShipments($this->order, $shipping_profile, $shipments);
// Store the IDs of removed shipments for submitPaneForm().
$pane_form['removed_shipments']['#value'] = array_map(function ($shipment) {
/** @var \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment */
return $shipment
->id();
}, $removed_shipments);
}
$single_shipment = count($shipments) === 1;
foreach ($shipments as $index => $shipment) {
/** @var \Drupal\commerce_shipping\Entity\ShipmentInterface $shipment */
$pane_form['shipments'][$index] = [
'#parents' => array_merge($pane_form['#parents'], [
'shipments',
$index,
]),
'#array_parents' => array_merge($pane_form['#parents'], [
'shipments',
$index,
]),
'#type' => $single_shipment ? 'container' : 'fieldset',
'#title' => $shipment
->getTitle(),
];
$form_display = EntityFormDisplay::collectRenderDisplay($shipment, 'checkout');
$form_display
->removeComponent('shipping_profile');
$form_display
->buildForm($shipment, $pane_form['shipments'][$index], $form_state);
$pane_form['shipments'][$index]['#shipment'] = $shipment;
}
// Update the shipments and save the order if no rate was explicitly
// selected, that usually occurs when changing addresses, this will ensure
// the default rate is selected/applied.
if (!$this
->hasRateSelected($pane_form, $form_state)) {
array_map(function (ShipmentInterface $shipment) {
if (!$shipment
->isNew()) {
$shipment
->save();
}
}, $shipments);
$this->order
->set('shipments', $shipments);
$this->order
->save();
}
return $pane_form;
}