commerce-8.x-2.8/modules/order/src/Element/ProfileSelect.php
modules/order/src/Element/ProfileSelect.php
<?php
namespace Drupal\commerce_order\Element;
use Drupal\commerce\Element\CommerceElementTrait;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element\RenderElement;
use Drupal\profile\Entity\ProfileInterface;
/**
* Provides a form element for selecting a customer profile.
*
* Usage example:
* @code
* $form['billing_profile'] = [
* '#type' => 'commerce_profile_select',
* '#default_value' => $profile,
* '#default_country' => 'FR',
* '#available_countries' => ['US', 'FR'],
* ];
* @endcode
* To access the profile in validation or submission callbacks, use
* $form['billing_profile']['#profile']. Due to Drupal core limitations the
* profile can't be accessed via $form_state->getValue('billing_profile').
*
* @RenderElement("commerce_profile_select")
*/
class ProfileSelect extends RenderElement {
use CommerceElementTrait;
/**
* {@inheritdoc}
*/
public function getInfo() {
$class = get_class($this);
return [
// The country to select if the address widget doesn't have a default.
'#default_country' => NULL,
// A list of country codes. If empty, all countries will be available.
'#available_countries' => [],
// The profile entity operated on. Required.
'#default_value' => NULL,
'#process' => [
[$class, 'attachElementSubmit'],
[$class, 'processForm'],
],
'#element_validate' => [
[$class, 'validateElementSubmit'],
[$class, 'validateForm'],
],
'#commerce_element_submit' => [
[$class, 'submitForm'],
],
'#theme_wrappers' => ['container'],
];
}
/**
* Builds the element form.
*
* @param array $element
* The form element being processed.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param array $complete_form
* The complete form structure.
*
* @throws \InvalidArgumentException
* Thrown when #default_value is empty or not an entity, or when
* #available_countries is not an array of country codes.
*
* @return array
* The processed form element.
*/
public static function processForm(array $element, FormStateInterface $form_state, array &$complete_form) {
if (empty($element['#default_value'])) {
throw new \InvalidArgumentException('The commerce_profile_select element requires the #default_value property.');
}
elseif (isset($element['#default_value']) && !($element['#default_value'] instanceof ProfileInterface)) {
throw new \InvalidArgumentException('The commerce_profile_select #default_value property must be a profile entity.');
}
if (!is_array($element['#available_countries'])) {
throw new \InvalidArgumentException('The commerce_profile_select #available_countries property must be an array.');
}
// Make sure that the specified default country is available.
if (!empty($element['#default_country']) && !empty($element['#available_countries'])) {
if (!in_array($element['#default_country'], $element['#available_countries'])) {
$element['#default_country'] = NULL;
}
}
$element['#profile'] = $element['#default_value'];
$form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default');
$form_display->buildForm($element['#profile'], $element, $form_state);
if (!empty($element['address']['widget'][0])) {
$widget_element = &$element['address']['widget'][0];
// Remove the details wrapper from the address widget.
$widget_element['#type'] = 'container';
// Provide a default country.
if (!empty($element['#default_country']) && empty($widget_element['address']['#default_value']['country_code'])) {
$widget_element['address']['#default_value']['country_code'] = $element['#default_country'];
}
// Limit the available countries.
if (!empty($element['#available_countries'])) {
$widget_element['address']['#available_countries'] = $element['#available_countries'];
}
}
return $element;
}
/**
* Validates the element form.
*
* @param array $element
* The form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @throws \Exception
* Thrown if button-level #validate handlers are detected on the parent
* form, as a protection against buggy behavior.
*/
public static function validateForm(array &$element, FormStateInterface $form_state) {
$form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default');
$form_display->extractFormValues($element['#profile'], $element, $form_state);
$form_display->validateFormValues($element['#profile'], $element, $form_state);
}
/**
* Submits the element form.
*
* @param array $element
* The form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*/
public static function submitForm(array &$element, FormStateInterface $form_state) {
$form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default');
$form_display->extractFormValues($element['#profile'], $element, $form_state);
$element['#profile']->save();
}
}
