From 645c20c0fc315dc1bfbb76098a0ad1547e93c9b1 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Sun, 16 Apr 2017 00:56:31 -0500 Subject: [PATCH 01/10] Combined profile select patch and profile reuse functionality --- modules/order/src/Element/ProfileSelect.php | 355 +++++++++++++++++++- 1 file changed, 347 insertions(+), 8 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 3b09fb18f7..b6c2d38729 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -3,9 +3,15 @@ namespace Drupal\commerce_order\Element; use Drupal\commerce\Element\CommerceElementBase; +use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\Entity\EntityFormDisplay; +use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; use Drupal\profile\Entity\ProfileInterface; +use Drupal\profile\Entity\Profile; +use Symfony\Component\HttpFoundation\Request; /** * Provides a form element for selecting a customer profile. @@ -17,6 +23,9 @@ * '#default_value' => $profile, * '#default_country' => 'FR', * '#available_countries' => ['US', 'FR'], + * '#reuse_profile_label' => $this->t('My billing address is the same as my shipping address.'), + * '#reuse_profile_source' => 'commerce_shipping_get_shipping_profile', + * '#reuse_profile_default' => FALSE, * ]; * @endcode * To access the profile in validation or submission callbacks, use @@ -37,6 +46,12 @@ public function getInfo() { '#default_country' => NULL, // A list of country codes. If empty, all countries will be available. '#available_countries' => [], + // The label for the reuse profile checkbox. If empty, checkbox is hidden. + '#reuse_profile_label' => NULL, + // The function to call to return the profile to reuse. + '#reuse_profile_source' => NULL, + // Whether the reuse checkbox should be checked by default. + '#reuse_profile_default' => FALSE, // The profile entity operated on. Required. '#default_value' => NULL, @@ -44,6 +59,9 @@ public function getInfo() { [$class, 'attachElementSubmit'], [$class, 'processForm'], ], + '#after_build' => [ + [$class, 'afterBuild'], + ], '#element_validate' => [ [$class, 'validateElementSubmit'], [$class, 'validateForm'], @@ -83,9 +101,91 @@ public static function processForm(array $element, FormStateInterface $form_stat throw new \InvalidArgumentException('The commerce_profile_select #available_countries property must be an array.'); } + // Initialize variables. $element['#profile'] = $element['#default_value']; - $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); - $form_display->buildForm($element['#profile'], $element, $form_state); + $bundle = $element['#default_value']->bundle(); + $default_profile_id = NULL; + // Fetch all profiles of the user for an addressbook functionality. + $profile_uid = $element['#default_value']->getOwnerId(); + // Anonymous users don't get an addressbook. + if ($profile_uid) { + $profile_ids = \Drupal::service('entity.query') + ->get('profile') + ->condition('uid', $profile_uid) + ->condition('type', $bundle) + ->condition('status', TRUE) + ->sort('profile_id', 'DESC') + ->execute(); + $profiles = Profile::loadMultiple($profile_ids); + $profile_options = []; + /** @var \Drupal\profile\Entity\Profile $profile_option */ + foreach ($profiles as $profile_option) { + if (empty($default_profile_id)) { + $default_profile_id = $profile_option->id(); + $default_profile = $profile_option; + } + $profile_options[$profile_option->id()] = $profile_option->label(); + } + $profile_options['new_profile'] = t('+ Enter a new profile'); + } + + $pane_id = $element['#name']; + $mode = 'view'; + $profile_selection_parents = $element['#parents']; + $profile_selection_parents[] = 'profile_selection'; + $profile_id = $form_state->getValue($profile_selection_parents); + $storage = $form_state->getStorage(); + + // User is adding a new profile. + if ($profile_id && $profile_id == 'new_profile') { + $mode = 'new'; + unset($storage['pane_' . $pane_id]); + } + // If an AJAX rebuild happened, we might have our data in form state. + elseif (!empty($storage['pane_' . $pane_id]['profile'])) { + $default_profile = $storage['pane_' . $pane_id]['profile']; + $default_profile_id = $default_profile->id(); + $mode = $storage['pane_' . $pane_id]['mode']; + $bundle = $default_profile->bundle(); + } + // Loading the page for the first time. + elseif ($element['#default_value']->id()) { + $default_profile = $element['#default_value']; + $default_profile_id = $default_profile->id(); + $bundle = $default_profile->bundle(); + } + + $ajax_wrapper_id = Html::getUniqueId('profile-select-ajax-wrapper'); + // Prefix and suffix used for Ajax replacement. + $element['#prefix'] = '
'; + $element['#suffix'] = '
'; + + $reuse_profile = (isset($storage['pane_' . $pane_id]['reuse_profile'])) + ? $storage['pane_' . $pane_id]['reuse_profile'] + : $element['#reuse_profile_default']; + + // Remember the current profile and mode in form state. + if (!empty($default_profile)) { + $storage['pane_' . $pane_id] = [ + 'profile' => $default_profile, + 'mode' => $mode, + 'reuse_profile' => $reuse_profile, + ]; + $form_state->setStorage($storage); + $element['#default_value'] = $default_profile; + } + // No profiles found or user wants to create a new one. + elseif (empty($profiles) || $mode == 'new') { + $values = [ + 'type' => $element['#default_value']->bundle(), + 'uid' => $element['#default_value']->getOwnerId(), + ]; + $default_profile = Profile::create($values); + $mode = 'new'; + } + + $form_display = EntityFormDisplay::collectRenderDisplay($element['#default_value'], 'default'); + $form_display->buildForm($element['#default_value'], $element, $form_state); if (!empty($element['address']['widget'][0])) { $widget_element = &$element['address']['widget'][0]; // Remove the details wrapper from the address widget. @@ -100,6 +200,117 @@ public static function processForm(array $element, FormStateInterface $form_stat } } + $called_class = get_called_class(); + $reuse_enabled = (!empty($element['#reuse_profile_label']) && !empty($element['#reuse_profile_source'])); + if ($reuse_enabled) { + $element['reuse_profile'] = [ + '#title' => $element['#reuse_profile_label'], + '#type' => 'checkbox', + '#weight' => -5, + '#default_value' => $reuse_profile, + '#ajax' => [ + 'callback' => [$called_class, 'profileAjax'], + 'wrapper' => $ajax_wrapper_id, + ], + '#element_validate' => [[$called_class, 'reuseProfileValidate']] + ]; + } + + if ($reuse_profile) { + foreach (Element::children($element) as $key) { + if (!in_array($key, ['reuse_profile'])) { + $element[$key]['#access'] = FALSE; + } + } + } else { + if (!empty($profile_uid) && $mode != 'edit' && !empty($profile_options) && count($profile_options) > 1) { + $element['profile_selection'] = [ + '#title' => t('Select a profile'), + '#options' => $profile_options, + '#type' => 'select', + '#weight' => -5, + '#default_value' => $default_profile_id, + '#ajax' => [ + 'callback' => [$called_class, 'profileAjax'], + 'wrapper' => $ajax_wrapper_id, + ], + '#element_validate' => [[$called_class, 'profileSelectValidate']], + ]; + } + + // Viewing a profile. + if ($mode == 'view') { + $view_builder = \Drupal::entityTypeManager() + ->getViewBuilder('profile'); + $content = $view_builder->view($default_profile, 'default'); + + $element['rendered_profile'] = [ + $content, + ]; + $element['edit_button'] = [ + '#type' => 'button', + '#name' => 'pane-' . $pane_id . '-edit', + '#value' => t('Edit'), + '#limit_validation_errors' => [], + '#ajax' => [ + 'callback' => [$called_class, 'profileAjax'], + 'wrapper' => $ajax_wrapper_id, + ], + '#element_validate' => [[$called_class, 'profileEditCancelValidate']], + ]; + foreach (Element::children($element) as $key) { + if (!in_array($key, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile'])) { + $element[$key]['#access'] = FALSE; + } + } + } + // Add the field widgets for an existing profile. + elseif (!empty($profiles) && $mode == 'edit') { + $element['cancel_button'] = [ + '#type' => 'button', + '#name' => 'pane-' . $pane_id . '-cancel', + '#value' => t('Return to profile selection'), + '#limit_validation_errors' => [], + '#ajax' => [ + 'callback' => [$called_class, 'profileAjax'], + 'wrapper' => $ajax_wrapper_id, + ], + '#element_validate' => [[$called_class, 'profileEditCancelValidate']], + '#weight' => 99, + ]; + } + } + + return $element; + } + + /** + * Element after_build callback. + * + * @param array $element + * The form element being processed. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @return array + * The built form element. + */ + public static function afterBuild(array $element, FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + if ($triggering_element) { + $parents = $triggering_element['#parents']; + $last_parent = array_pop($parents); + if ($last_parent == 'edit_button') { + foreach (Element::children($element) as $key) { + if (in_array($key, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile'])) { + $element[$key]['#access'] = FALSE; + } + else { + $element[$key]['#access'] = TRUE; + } + } + } + } return $element; } @@ -116,9 +327,17 @@ public static function processForm(array $element, FormStateInterface $form_stat * 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); + $pane_id = $element['#name']; + $storage = $form_state->getStorage(); + if (!isset($storage['pane_' . $pane_id]['reuse_profile']) || !$storage['pane_' . $pane_id]['reuse_profile']) { + $parents = $form_state->getTriggeringElement()['#parents']; + $triggering_last_parent = array_pop($parents); + if (!in_array($triggering_last_parent, ['edit_button', 'cancel_button'])) { + $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); + $form_display->extractFormValues($element['#profile'], $element, $form_state); + $form_display->validateFormValues($element['#profile'], $element, $form_state); + } + } } /** @@ -130,9 +349,129 @@ public static function validateForm(array &$element, FormStateInterface $form_st * 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(); + $pane_id = $element['#name']; + $storage = $form_state->getStorage(); + if (isset($storage['pane_' . $pane_id]['reuse_profile']) && $storage['pane_' . $pane_id]['reuse_profile']) { + if (is_numeric($element['#reuse_profile_source'])) { + $profile = \Drupal::entityTypeManager()->getStorage('profile')->load($element['#reuse_profile_source']); + } else { + // Load profile from a callback + $profile = call_user_func($element['#reuse_profile_source'], $element, $form_state, $form_state->getCompleteForm()); + } + $element['#profile'] = $profile; + } elseif (isset($storage['pane_' . $pane_id]) && in_array($storage['pane_' . $pane_id]['mode'], ['new', 'edit'])) { + $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); + $form_display->extractFormValues($element['#profile'], $element, $form_state); + $element['#profile']->save(); + } + } + + /** + * Reuse profile AJAX callback. + * + * @param array $form + * The complete form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * @param \Symfony\Component\HttpFoundation\Request $request + * The Request object. + * + * @return array + * The form element replace the wrapper with. + */ + public static function profileAjax(array &$form, FormStateInterface $form_state, Request $request) { + $triggering_element = $form_state->getTriggeringElement(); + $array_parents = $triggering_element['#array_parents']; + array_pop($array_parents); + return NestedArray::getValue($form, $array_parents); + } + + /** + * The #element_validate callback for the reuse profile checkbox. + * + * @param array $element + * The form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public static function reuseProfileValidate(array $element, FormStateInterface $form_state) { + $form = $form_state->getCompleteForm(); + $profile_element_parents = $element['#parents']; + array_pop($profile_element_parents); + $profile_element = NestedArray::getValue($form, $profile_element_parents); + $pane_id = $profile_element['#name']; + $storage = $form_state->getStorage(); + + $storage['pane_' . $pane_id]['reuse_profile'] = $element['#value']; + $form_state->setStorage($storage); + } + + /** + * The #element_validate callback for the profiles dropdown select. + * + * @param array $element + * The form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public static function profileSelectValidate(array $element, FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + if (in_array('profile_selection', $triggering_element['#array_parents']) && $triggering_element['#id'] == $element['#id']) { + $form = $form_state->getCompleteForm(); + $profile_element_parents = $element['#parents']; + array_pop($profile_element_parents); + $profile_element = NestedArray::getValue($form, $profile_element_parents); + $pane_id = $profile_element['#name']; + $storage = $form_state->getStorage(); + + // If the user wants to enter a new profile. + if ($element['#value'] == 'new_profile') { + $storage['pane_' . $pane_id]['mode'] = 'new'; + $values = [ + 'type' => $profile_element['#profile']->bundle(), + 'uid' => $profile_element['#profile']->getOwnerId(), + ]; + $profile = Profile::create($values); + $storage['pane_' . $pane_id]['profile'] = $profile; + } + else { + $storage['pane_' . $pane_id]['mode'] = 'view'; + $profile_id = $form_state->getValue($element['#parents']); + $storage['pane_' . $pane_id]['profile'] = Profile::load($profile_id); + } + $form_state->setStorage($storage); + } + } + + /** + * The #element_validate callback for the edit and cancel buttons. + * + * @param array $element + * The form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + public static function profileEditCancelValidate(array &$element, FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + if ($triggering_element && $triggering_element['#id'] === $element['#id']) { + $array_parents = $triggering_element['#array_parents']; + $last_parent = array_pop($array_parents); + if (in_array($last_parent, ['edit_button', 'cancel_button'])) { + $complete_form = $form_state->getCompleteForm(); + $parents = $element['#parents']; + array_pop($parents); + $element = NestedArray::getValue($complete_form, $parents); + $pane_id = $element['#name']; + $storage = $form_state->getStorage(); + if ($last_parent == 'edit_button') { + $storage['pane_' . $pane_id]['mode'] = 'edit'; + } + else { + unset($storage['pane_' . $pane_id]); + } + $form_state->setStorage($storage); + } + } } } From 4ff650befae4df53a00ee558e95f36f020479fb0 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Sun, 16 Apr 2017 13:44:25 -0500 Subject: [PATCH 02/10] Ensure reuse_profile checkbox state is maintained in form state storage --- modules/order/src/Element/ProfileSelect.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index b6c2d38729..af911f9a78 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -135,6 +135,9 @@ public static function processForm(array $element, FormStateInterface $form_stat $profile_selection_parents[] = 'profile_selection'; $profile_id = $form_state->getValue($profile_selection_parents); $storage = $form_state->getStorage(); + $reuse_profile = (isset($storage['pane_' . $pane_id]['reuse_profile'])) + ? $storage['pane_' . $pane_id]['reuse_profile'] + : $element['#reuse_profile_default']; // User is adding a new profile. if ($profile_id && $profile_id == 'new_profile') { @@ -160,18 +163,12 @@ public static function processForm(array $element, FormStateInterface $form_stat $element['#prefix'] = '
'; $element['#suffix'] = '
'; - $reuse_profile = (isset($storage['pane_' . $pane_id]['reuse_profile'])) - ? $storage['pane_' . $pane_id]['reuse_profile'] - : $element['#reuse_profile_default']; - // Remember the current profile and mode in form state. if (!empty($default_profile)) { $storage['pane_' . $pane_id] = [ 'profile' => $default_profile, 'mode' => $mode, - 'reuse_profile' => $reuse_profile, ]; - $form_state->setStorage($storage); $element['#default_value'] = $default_profile; } // No profiles found or user wants to create a new one. @@ -200,6 +197,10 @@ public static function processForm(array $element, FormStateInterface $form_stat } } + // Maintain the state of the Reuse Profile checkbox + $storage['pane_' . $pane_id]['reuse_profile'] = $reuse_profile; + $form_state->setStorage($storage); + $called_class = get_called_class(); $reuse_enabled = (!empty($element['#reuse_profile_label']) && !empty($element['#reuse_profile_source'])); if ($reuse_enabled) { From 3ddcbb6316a15eda91f8046936359c0b9b8dd7b6 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Tue, 18 Apr 2017 19:22:34 -0500 Subject: [PATCH 03/10] Ensure mode key exists before accessing it --- modules/order/src/Element/ProfileSelect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index af911f9a78..f54d2d6df1 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -360,7 +360,7 @@ public static function submitForm(array &$element, FormStateInterface $form_stat $profile = call_user_func($element['#reuse_profile_source'], $element, $form_state, $form_state->getCompleteForm()); } $element['#profile'] = $profile; - } elseif (isset($storage['pane_' . $pane_id]) && in_array($storage['pane_' . $pane_id]['mode'], ['new', 'edit'])) { + } elseif (isset($storage['pane_' . $pane_id]['mode']) && in_array($storage['pane_' . $pane_id]['mode'], ['new', 'edit'])) { $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); $form_display->extractFormValues($element['#profile'], $element, $form_state); $element['#profile']->save(); From b743662b8e468222defcaa4265f9a7ec444058c1 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Wed, 19 Apr 2017 12:56:54 -0500 Subject: [PATCH 04/10] Force "edit" mode if anonymous and a profile is provided --- modules/order/src/Element/ProfileSelect.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index f54d2d6df1..0e9d5c4c5c 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -107,6 +107,8 @@ public static function processForm(array $element, FormStateInterface $form_stat $default_profile_id = NULL; // Fetch all profiles of the user for an addressbook functionality. $profile_uid = $element['#default_value']->getOwnerId(); + $profiles = []; + // Anonymous users don't get an addressbook. if ($profile_uid) { $profile_ids = \Drupal::service('entity.query') @@ -158,6 +160,10 @@ public static function processForm(array $element, FormStateInterface $form_stat $bundle = $default_profile->bundle(); } + if (empty($profiles) && !empty($default_profile)) { + $mode = 'edit'; + } + $ajax_wrapper_id = Html::getUniqueId('profile-select-ajax-wrapper'); // Prefix and suffix used for Ajax replacement. $element['#prefix'] = '
'; From d82e445db3b2a676293e6c7eed18c030e433768b Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Wed, 19 Apr 2017 12:58:58 -0500 Subject: [PATCH 05/10] Move new logic into previous conditional --- modules/order/src/Element/ProfileSelect.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 0e9d5c4c5c..6ca18e103b 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -158,10 +158,10 @@ public static function processForm(array $element, FormStateInterface $form_stat $default_profile = $element['#default_value']; $default_profile_id = $default_profile->id(); $bundle = $default_profile->bundle(); - } - if (empty($profiles) && !empty($default_profile)) { - $mode = 'edit'; + if (empty($profiles) && !empty($default_profile)) { + $mode = 'edit'; + } } $ajax_wrapper_id = Html::getUniqueId('profile-select-ajax-wrapper'); From e34a8aac29e9113d1e703870e84760069ecac5dd Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Sun, 23 Apr 2017 13:53:20 -0500 Subject: [PATCH 06/10] New version --- modules/order/src/Element/ProfileSelect.php | 428 ++++++++++++-------- 1 file changed, 250 insertions(+), 178 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 6ca18e103b..902f05502c 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -2,13 +2,14 @@ namespace Drupal\commerce_order\Element; -use Drupal\commerce\Element\CommerceElementBase; +use Drupal\commerce\Element\CommerceElementTrait; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\Entity\EntityFormDisplay; -use Drupal\Core\Form\FormState; +use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; +use Drupal\Core\Render\Element\RenderElement; use Drupal\profile\Entity\ProfileInterface; use Drupal\profile\Entity\Profile; use Symfony\Component\HttpFoundation\Request; @@ -23,6 +24,7 @@ * '#default_value' => $profile, * '#default_country' => 'FR', * '#available_countries' => ['US', 'FR'], + * '#profile_view_mode' => 'default', * '#reuse_profile_label' => $this->t('My billing address is the same as my shipping address.'), * '#reuse_profile_source' => 'commerce_shipping_get_shipping_profile', * '#reuse_profile_default' => FALSE, @@ -34,7 +36,9 @@ * * @RenderElement("commerce_profile_select") */ -class ProfileSelect extends CommerceElementBase { +class ProfileSelect extends RenderElement { + + use CommerceElementTrait; /** * {@inheritdoc} @@ -46,13 +50,14 @@ public function getInfo() { '#default_country' => NULL, // A list of country codes. If empty, all countries will be available. '#available_countries' => [], + // The view mode to render existing profiles with. + '#profile_view_mode' => 'default', // The label for the reuse profile checkbox. If empty, checkbox is hidden. '#reuse_profile_label' => NULL, // The function to call to return the profile to reuse. '#reuse_profile_source' => NULL, // Whether the reuse checkbox should be checked by default. '#reuse_profile_default' => FALSE, - // The profile entity operated on. Required. '#default_value' => NULL, '#process' => [ @@ -101,100 +106,57 @@ public static function processForm(array $element, FormStateInterface $form_stat throw new \InvalidArgumentException('The commerce_profile_select #available_countries property must be an array.'); } - // Initialize variables. - $element['#profile'] = $element['#default_value']; - $bundle = $element['#default_value']->bundle(); - $default_profile_id = NULL; - // Fetch all profiles of the user for an addressbook functionality. - $profile_uid = $element['#default_value']->getOwnerId(); - $profiles = []; - - // Anonymous users don't get an addressbook. - if ($profile_uid) { - $profile_ids = \Drupal::service('entity.query') - ->get('profile') - ->condition('uid', $profile_uid) - ->condition('type', $bundle) - ->condition('status', TRUE) - ->sort('profile_id', 'DESC') - ->execute(); - $profiles = Profile::loadMultiple($profile_ids); - $profile_options = []; - /** @var \Drupal\profile\Entity\Profile $profile_option */ - foreach ($profiles as $profile_option) { - if (empty($default_profile_id)) { - $default_profile_id = $profile_option->id(); - $default_profile = $profile_option; - } - $profile_options[$profile_option->id()] = $profile_option->label(); - } - $profile_options['new_profile'] = t('+ Enter a new profile'); - } - - $pane_id = $element['#name']; - $mode = 'view'; - $profile_selection_parents = $element['#parents']; - $profile_selection_parents[] = 'profile_selection'; - $profile_id = $form_state->getValue($profile_selection_parents); - $storage = $form_state->getStorage(); - $reuse_profile = (isset($storage['pane_' . $pane_id]['reuse_profile'])) - ? $storage['pane_' . $pane_id]['reuse_profile'] - : $element['#reuse_profile_default']; - - // User is adding a new profile. - if ($profile_id && $profile_id == 'new_profile') { - $mode = 'new'; - unset($storage['pane_' . $pane_id]); - } - // If an AJAX rebuild happened, we might have our data in form state. - elseif (!empty($storage['pane_' . $pane_id]['profile'])) { - $default_profile = $storage['pane_' . $pane_id]['profile']; - $default_profile_id = $default_profile->id(); - $mode = $storage['pane_' . $pane_id]['mode']; - $bundle = $default_profile->bundle(); - } - // Loading the page for the first time. - elseif ($element['#default_value']->id()) { - $default_profile = $element['#default_value']; - $default_profile_id = $default_profile->id(); - $bundle = $default_profile->bundle(); - - if (empty($profiles) && !empty($default_profile)) { - $mode = 'edit'; - } + // Assign a name if it's unset. + if (empty($element['#name'])) { + list($name) = explode('--', $element['#id']); + $element['#name'] = 'profile-select--' . $name; } + // Initialize variables. $ajax_wrapper_id = Html::getUniqueId('profile-select-ajax-wrapper'); - // Prefix and suffix used for Ajax replacement. $element['#prefix'] = '
'; $element['#suffix'] = '
'; + $called_class = get_called_class(); + $pane_storage = self::getPaneStorage($element, $form_state); + $mode = self::getMode($element, $form_state); + $new_form = empty($pane_storage['profile']); + $default_profile = ($new_form || $mode === 'new') + ? $element['#default_value'] + : $pane_storage['profile']; + $profiles = self::getExistingProfiles($default_profile); - // Remember the current profile and mode in form state. - if (!empty($default_profile)) { - $storage['pane_' . $pane_id] = [ - 'profile' => $default_profile, - 'mode' => $mode, - ]; - $element['#default_value'] = $default_profile; + // If no account profiles returned but we're viewing one, edit it instead. + if ($mode == 'view' && empty($profiles)) { + $mode = 'edit'; } - // No profiles found or user wants to create a new one. - elseif (empty($profiles) || $mode == 'new') { - $values = [ - 'type' => $element['#default_value']->bundle(), - 'uid' => $element['#default_value']->getOwnerId(), - ]; - $default_profile = Profile::create($values); - $mode = 'new'; + + // Select existing user profile if this is a new form. + if ($new_form && !$default_profile->id() && !empty($profiles)) { + $default_profile = reset($profiles); + $mode = 'view'; + } + + // Create a new profile if user has chosen to do so. + if (!$new_form && $mode == 'new') { + $default_profile = Profile::create([ + 'type' => $default_profile->bundle(), + 'uid' => $default_profile->getOwnerId(), + ]); } - $form_display = EntityFormDisplay::collectRenderDisplay($element['#default_value'], 'default'); - $form_display->buildForm($element['#default_value'], $element, $form_state); + // Assign the right profile to the element. + $element['#default_value'] = $default_profile; + $element['#profile'] = $default_profile; + + // Set default address field options. + $form_display = EntityFormDisplay::collectRenderDisplay($default_profile, 'default'); + $form_display->buildForm($default_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'])) { + if (!empty($element['#default_country']) && $mode === 'new') { $widget_element['address']['#default_value']['country_code'] = $element['#default_country']; } // Limit the available countries. @@ -203,13 +165,11 @@ public static function processForm(array $element, FormStateInterface $form_stat } } - // Maintain the state of the Reuse Profile checkbox - $storage['pane_' . $pane_id]['reuse_profile'] = $reuse_profile; - $form_state->setStorage($storage); - - $called_class = get_called_class(); - $reuse_enabled = (!empty($element['#reuse_profile_label']) && !empty($element['#reuse_profile_source'])); - if ($reuse_enabled) { + // Set up profile reuse functionality. + $reuse_profile = (isset($pane_storage['reuse_profile'])) + ? $pane_storage['reuse_profile'] + : $element['#reuse_profile_default']; + if ((!empty($element['#reuse_profile_label']) && !empty($element['#reuse_profile_source']))) { $element['reuse_profile'] = [ '#title' => $element['#reuse_profile_label'], '#type' => 'checkbox', @@ -219,24 +179,29 @@ public static function processForm(array $element, FormStateInterface $form_stat 'callback' => [$called_class, 'profileAjax'], 'wrapper' => $ajax_wrapper_id, ], - '#element_validate' => [[$called_class, 'reuseProfileValidate']] + '#element_validate' => [[$called_class, 'profileReuseValidate']] ]; } + // Hide all profile fields except the checkbox if reuse_profile is checked. if ($reuse_profile) { - foreach (Element::children($element) as $key) { - if (!in_array($key, ['reuse_profile'])) { - $element[$key]['#access'] = FALSE; + self::hideProfileFields($element, ['reuse_profile']); + } + else { + // Output a profile select element. + if ($mode != 'edit' && !empty($profiles)) { + $profile_options = []; + foreach ($profiles as $profile_option) { + $profile_options[$profile_option->id()] = $profile_option->label(); } - } - } else { - if (!empty($profile_uid) && $mode != 'edit' && !empty($profile_options) && count($profile_options) > 1) { + $profile_options['new_profile'] = t('+ Enter a new profile'); + $element['profile_selection'] = [ '#title' => t('Select a profile'), '#options' => $profile_options, '#type' => 'select', '#weight' => -5, - '#default_value' => $default_profile_id, + '#default_value' => $default_profile->id() ?: 'new_profile', '#ajax' => [ 'callback' => [$called_class, 'profileAjax'], 'wrapper' => $ajax_wrapper_id, @@ -247,16 +212,14 @@ public static function processForm(array $element, FormStateInterface $form_stat // Viewing a profile. if ($mode == 'view') { - $view_builder = \Drupal::entityTypeManager() - ->getViewBuilder('profile'); - $content = $view_builder->view($default_profile, 'default'); - $element['rendered_profile'] = [ - $content, + \Drupal::entityTypeManager() + ->getViewBuilder('profile') + ->view($default_profile, $element['#profile_view_mode']), ]; $element['edit_button'] = [ '#type' => 'button', - '#name' => 'pane-' . $pane_id . '-edit', + '#name' => 'pane-' . $element['#name'] . '-edit', '#value' => t('Edit'), '#limit_validation_errors' => [], '#ajax' => [ @@ -265,18 +228,14 @@ public static function processForm(array $element, FormStateInterface $form_stat ], '#element_validate' => [[$called_class, 'profileEditCancelValidate']], ]; - foreach (Element::children($element) as $key) { - if (!in_array($key, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile'])) { - $element[$key]['#access'] = FALSE; - } - } + self::hideProfileFields($element, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile']); } - // Add the field widgets for an existing profile. + // Editing an existing profile. elseif (!empty($profiles) && $mode == 'edit') { $element['cancel_button'] = [ '#type' => 'button', - '#name' => 'pane-' . $pane_id . '-cancel', - '#value' => t('Return to profile selection'), + '#name' => 'pane-' . $element['#name'] . '-cancel', + '#value' => t('Cancel and return to profile selection'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [$called_class, 'profileAjax'], @@ -288,6 +247,12 @@ public static function processForm(array $element, FormStateInterface $form_stat } } + // Maintain the state of the settings before returning. + self::setPaneStorage($element, $form_state, [ + 'profile' => $default_profile, + 'mode' => $mode, + 'reuse_profile' => $reuse_profile, + ]); return $element; } @@ -304,18 +269,11 @@ public static function processForm(array $element, FormStateInterface $form_stat */ public static function afterBuild(array $element, FormStateInterface $form_state) { $triggering_element = $form_state->getTriggeringElement(); - if ($triggering_element) { - $parents = $triggering_element['#parents']; - $last_parent = array_pop($parents); + if (!empty($triggering_element['#parents'])) { + $last_parent = array_pop($triggering_element['#parents']); if ($last_parent == 'edit_button') { - foreach (Element::children($element) as $key) { - if (in_array($key, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile'])) { - $element[$key]['#access'] = FALSE; - } - else { - $element[$key]['#access'] = TRUE; - } - } + $retain = ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile']; + self::hideProfileFields($element, $retain, TRUE); } } return $element; @@ -334,16 +292,13 @@ public static function afterBuild(array $element, FormStateInterface $form_state * form, as a protection against buggy behavior. */ public static function validateForm(array &$element, FormStateInterface $form_state) { - $pane_id = $element['#name']; - $storage = $form_state->getStorage(); - if (!isset($storage['pane_' . $pane_id]['reuse_profile']) || !$storage['pane_' . $pane_id]['reuse_profile']) { - $parents = $form_state->getTriggeringElement()['#parents']; - $triggering_last_parent = array_pop($parents); - if (!in_array($triggering_last_parent, ['edit_button', 'cancel_button'])) { - $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); - $form_display->extractFormValues($element['#profile'], $element, $form_state); - $form_display->validateFormValues($element['#profile'], $element, $form_state); - } + $parents = $form_state->getTriggeringElement()['#parents']; + $last_parent = array_pop($parents); + $pane_storage = self::getPaneStorage($element, $form_state); + if (!$pane_storage['reuse_profile'] && !in_array($last_parent, ['edit_button', 'cancel_button'])) { + $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); + $form_display->extractFormValues($element['#profile'], $element, $form_state); + $form_display->validateFormValues($element['#profile'], $element, $form_state); } } @@ -354,19 +309,23 @@ public static function validateForm(array &$element, FormStateInterface $form_st * The form element. * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. + * + * @throws \Drupal\Core\Entity\EntityStorageException */ public static function submitForm(array &$element, FormStateInterface $form_state) { - $pane_id = $element['#name']; - $storage = $form_state->getStorage(); - if (isset($storage['pane_' . $pane_id]['reuse_profile']) && $storage['pane_' . $pane_id]['reuse_profile']) { - if (is_numeric($element['#reuse_profile_source'])) { - $profile = \Drupal::entityTypeManager()->getStorage('profile')->load($element['#reuse_profile_source']); - } else { - // Load profile from a callback - $profile = call_user_func($element['#reuse_profile_source'], $element, $form_state, $form_state->getCompleteForm()); + $pane_storage = self::getPaneStorage($element, $form_state); + if ($pane_storage['reuse_profile']) { + // Load the current profile by ID or by callback + $profile = (is_numeric($element['#reuse_profile_source'])) + ? \Drupal::entityTypeManager()->getStorage('profile')->load($element['#reuse_profile_source']) + : call_user_func($element['#reuse_profile_source'], $element, $form_state, $form_state->getCompleteForm()); + // There's no valid way to reuse a profile if one is not found. + if (!$profile instanceof ProfileInterface) { + throw new EntityStorageException('The profile to reuse could not be determined from the provided arguments.'); } $element['#profile'] = $profile; - } elseif (isset($storage['pane_' . $pane_id]['mode']) && in_array($storage['pane_' . $pane_id]['mode'], ['new', 'edit'])) { + } + elseif (isset($pane_storage['mode']) && in_array($pane_storage['mode'], ['new', 'edit'])) { $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); $form_display->extractFormValues($element['#profile'], $element, $form_state); $element['#profile']->save(); @@ -374,7 +333,7 @@ public static function submitForm(array &$element, FormStateInterface $form_stat } /** - * Reuse profile AJAX callback. + * Profile AJAX callback. * * @param array $form * The complete form array. @@ -401,16 +360,12 @@ public static function profileAjax(array &$form, FormStateInterface $form_state, * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ - public static function reuseProfileValidate(array $element, FormStateInterface $form_state) { + public static function profileReuseValidate(array $element, FormStateInterface $form_state) { $form = $form_state->getCompleteForm(); $profile_element_parents = $element['#parents']; array_pop($profile_element_parents); $profile_element = NestedArray::getValue($form, $profile_element_parents); - $pane_id = $profile_element['#name']; - $storage = $form_state->getStorage(); - - $storage['pane_' . $pane_id]['reuse_profile'] = $element['#value']; - $form_state->setStorage($storage); + self::setPaneStorage($profile_element, $form_state, 'reuse_profile', $element['#value']); } /** @@ -428,25 +383,23 @@ public static function profileSelectValidate(array $element, FormStateInterface $profile_element_parents = $element['#parents']; array_pop($profile_element_parents); $profile_element = NestedArray::getValue($form, $profile_element_parents); - $pane_id = $profile_element['#name']; - $storage = $form_state->getStorage(); - - // If the user wants to enter a new profile. - if ($element['#value'] == 'new_profile') { - $storage['pane_' . $pane_id]['mode'] = 'new'; - $values = [ - 'type' => $profile_element['#profile']->bundle(), - 'uid' => $profile_element['#profile']->getOwnerId(), - ]; - $profile = Profile::create($values); - $storage['pane_' . $pane_id]['profile'] = $profile; - } - else { - $storage['pane_' . $pane_id]['mode'] = 'view'; + $pane_storage = self::getPaneStorage($profile_element, $form_state); + $profile_storage = \Drupal::entityTypeManager()->getStorage('profile'); + $create_profile = ($element['#value'] == 'new_profile'); + if ($create_profile) { + /** @var ProfileInterface $existing_profile */ + $existing_profile = $profile_element['#profile']; + $profile = $profile_storage->create([ + 'type' => $existing_profile->bundle(), + 'uid' => $existing_profile->getOwnerId(), + ]); + } else { $profile_id = $form_state->getValue($element['#parents']); - $storage['pane_' . $pane_id]['profile'] = Profile::load($profile_id); + $profile = $profile_storage->load($profile_id); } - $form_state->setStorage($storage); + $pane_storage['profile'] = $profile; + $pane_storage['mode'] = $create_profile ? 'new' : 'view'; + self::setPaneStorage($profile_element, $form_state, $pane_storage); } } @@ -458,7 +411,7 @@ public static function profileSelectValidate(array $element, FormStateInterface * @param \Drupal\Core\Form\FormStateInterface $form_state * The current state of the form. */ - public static function profileEditCancelValidate(array &$element, FormStateInterface $form_state) { + public static function profileEditCancelValidate(array $element, FormStateInterface $form_state) { $triggering_element = $form_state->getTriggeringElement(); if ($triggering_element && $triggering_element['#id'] === $element['#id']) { $array_parents = $triggering_element['#array_parents']; @@ -467,18 +420,137 @@ public static function profileEditCancelValidate(array &$element, FormStateInter $complete_form = $form_state->getCompleteForm(); $parents = $element['#parents']; array_pop($parents); - $element = NestedArray::getValue($complete_form, $parents); - $pane_id = $element['#name']; - $storage = $form_state->getStorage(); - if ($last_parent == 'edit_button') { - $storage['pane_' . $pane_id]['mode'] = 'edit'; - } - else { - unset($storage['pane_' . $pane_id]); - } - $form_state->setStorage($storage); + $profile_element = NestedArray::getValue($complete_form, $parents); + $mode = ($last_parent == 'edit_button') ? 'edit' : 'view'; + self::setPaneStorage($profile_element, $form_state, 'mode', $mode); } } } + /** + * Get the current pane storage values from the form state, or the defaults. + * + * @param array $element + * The element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * The pane storage array. + */ + protected static function getPaneStorage(array &$element, FormStateInterface $form_state) { + $storage = $form_state->getStorage(); + $pane_storage = isset($storage['pane_' . $element['#name']]) + ? $storage['pane_' . $element['#name']] + : []; + $defaults = [ + 'profile' => NULL, + 'reuse_profile' => NULL, + 'mode' => 'view' + ]; + return $pane_storage + $defaults; + } + + /** + * Stores one or all values to the pane storage. + * + * @param array $element + * The element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * @param $keyOrValues + * Either the key to set, or an array to replace the entire pane storage + * with. + * @param null $value + * The new value to set if setting a single key. Used only if $keyOrValue + * is not an array. + */ + protected static function setPaneStorage(array &$element, FormStateInterface $form_state, $keyOrValues, $value = NULL) { + if (is_array($keyOrValues)) { + $pane_storage = $keyOrValues; + } else { + $pane_storage = self::getPaneStorage($element, $form_state); + $pane_storage[$keyOrValues] = $value; + } + $storage = $form_state->getStorage(); + $storage['pane_' . $element['#name']] = $pane_storage; + $form_state->setStorage($storage); + } + + /** + * Hides fields from the element which should not be visible. + * + * @param array $element + * The element. + * @param array $retain + * An array of child element keys to keep visible. + * @param bool $force_retained + * Whether or not to force retained fields to stay visible. + */ + protected static function hideProfileFields(array &$element, $retain = [], $force_retained = FALSE) { + foreach (Element::children($element) as $key) { + if (!in_array($key, $retain)) { + $element[$key]['#access'] = FALSE; + } elseif ($force_retained) { + $element[$key]['#access'] = TRUE; + } + } + } + + /** + * Get the current mode of the profile select element. + * + * @param array $element + * The element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return string + * The current mode. + */ + protected static function getMode(array $element, FormStateInterface $form_state) { + $pane_storage = self::getPaneStorage($element, $form_state); + $profile_selection_parents = $element['#parents']; + $profile_selection_parents[] = 'profile_selection'; + $selected_profile = $form_state->getValue($profile_selection_parents); + $mode = 'view'; + // User is adding a new profile. + if (!empty($selected_profile) && $selected_profile == 'new_profile') { + $mode = 'new'; + } + // If an AJAX rebuild happened, we might have our data in form state. + elseif (!empty($pane_storage['profile'])) { + $mode = $pane_storage['mode']; + } + elseif (!empty($element['#default_value']) && $element['#default_value'] instanceof ProfileInterface && !$element['#default_value']->id()) { + $mode = 'new'; + } + return $mode; + } + + /** + * Loads the current user's profiles. + * + * @param ProfileInterface $default_profile + * The default profile for the element. + * + * @return ProfileInterface[] + * The profiles. + */ + protected static function getExistingProfiles(ProfileInterface $default_profile) { + $profiles = []; + if ($default_profile->getOwnerId() > 0) { + $profile_ids = \Drupal::service('entity.query') + ->get('profile') + ->condition('uid', $default_profile->getOwnerId()) + ->condition('type', $default_profile->bundle()) + ->condition('status', TRUE) + ->sort('profile_id', 'DESC') + ->execute(); + $profiles = Profile::loadMultiple($profile_ids); + } + return $profiles; + } + } + From 2c4b22f93d7815e0323218f1675d9c1928e0b97f Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Sun, 23 Apr 2017 14:29:03 -0500 Subject: [PATCH 07/10] Resolve issue with patch not applying --- modules/order/src/Element/ProfileSelect.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 902f05502c..045e88ba58 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -2,16 +2,15 @@ namespace Drupal\commerce_order\Element; -use Drupal\commerce\Element\CommerceElementTrait; use Drupal\Component\Utility\Html; use Drupal\Component\Utility\NestedArray; +use Drupal\commerce\Element\CommerceElementTrait; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Element; use Drupal\Core\Render\Element\RenderElement; use Drupal\profile\Entity\ProfileInterface; -use Drupal\profile\Entity\Profile; use Symfony\Component\HttpFoundation\Request; /** @@ -138,7 +137,7 @@ public static function processForm(array $element, FormStateInterface $form_stat // Create a new profile if user has chosen to do so. if (!$new_form && $mode == 'new') { - $default_profile = Profile::create([ + $default_profile = \Drupal::entityTypeManager()->getStorage('profile')->create([ 'type' => $default_profile->bundle(), 'uid' => $default_profile->getOwnerId(), ]); @@ -547,7 +546,7 @@ protected static function getExistingProfiles(ProfileInterface $default_profile) ->condition('status', TRUE) ->sort('profile_id', 'DESC') ->execute(); - $profiles = Profile::loadMultiple($profile_ids); + $profiles = \Drupal::entityTypeManager()->getStorage('profile')->loadMultiple($profile_ids); } return $profiles; } From 3261b8ee8868eff1af95f51a2cedcc8900cf512b Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Tue, 25 Apr 2017 18:51:36 -0500 Subject: [PATCH 08/10] Refactored code and resolved issue with previously selected profile not being reused --- modules/order/src/Element/ProfileSelect.php | 129 +++++++++++++------- 1 file changed, 85 insertions(+), 44 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index 045e88ba58..ab2bc3e05d 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -117,35 +117,16 @@ public static function processForm(array $element, FormStateInterface $form_stat $element['#suffix'] = '
'; $called_class = get_called_class(); $pane_storage = self::getPaneStorage($element, $form_state); - $mode = self::getMode($element, $form_state); - $new_form = empty($pane_storage['profile']); - $default_profile = ($new_form || $mode === 'new') - ? $element['#default_value'] - : $pane_storage['profile']; - $profiles = self::getExistingProfiles($default_profile); - - // If no account profiles returned but we're viewing one, edit it instead. - if ($mode == 'view' && empty($profiles)) { - $mode = 'edit'; - } - - // Select existing user profile if this is a new form. - if ($new_form && !$default_profile->id() && !empty($profiles)) { - $default_profile = reset($profiles); - $mode = 'view'; - } - - // Create a new profile if user has chosen to do so. - if (!$new_form && $mode == 'new') { - $default_profile = \Drupal::entityTypeManager()->getStorage('profile')->create([ - 'type' => $default_profile->bundle(), - 'uid' => $default_profile->getOwnerId(), - ]); - } - - // Assign the right profile to the element. + $profiles = self::getExistingProfiles($element['#default_value']); + $mode = self::getMode($element, $form_state, $profiles); + $default_profile = self::getDefaultProfile($element, $form_state, $mode, $profiles); + $selected_profile = self::getProfileSelectValue($element, $form_state); $element['#default_value'] = $default_profile; $element['#profile'] = $default_profile; + // Set up profile reuse functionality. + $reuse_profile = (isset($pane_storage['reuse_profile'])) + ? $pane_storage['reuse_profile'] + : $element['#reuse_profile_default']; // Set default address field options. $form_display = EntityFormDisplay::collectRenderDisplay($default_profile, 'default'); @@ -164,10 +145,7 @@ public static function processForm(array $element, FormStateInterface $form_stat } } - // Set up profile reuse functionality. - $reuse_profile = (isset($pane_storage['reuse_profile'])) - ? $pane_storage['reuse_profile'] - : $element['#reuse_profile_default']; + // Show the profile reuse checkbox if enabled. if ((!empty($element['#reuse_profile_label']) && !empty($element['#reuse_profile_source']))) { $element['reuse_profile'] = [ '#title' => $element['#reuse_profile_label'], @@ -182,7 +160,7 @@ public static function processForm(array $element, FormStateInterface $form_stat ]; } - // Hide all profile fields except the checkbox if reuse_profile is checked. + // Hide the profile fields if profile reuse checkbox is checked. if ($reuse_profile) { self::hideProfileFields($element, ['reuse_profile']); } @@ -209,7 +187,6 @@ public static function processForm(array $element, FormStateInterface $form_stat ]; } - // Viewing a profile. if ($mode == 'view') { $element['rendered_profile'] = [ \Drupal::entityTypeManager() @@ -251,6 +228,7 @@ public static function processForm(array $element, FormStateInterface $form_stat 'profile' => $default_profile, 'mode' => $mode, 'reuse_profile' => $reuse_profile, + 'selected_profile' => $selected_profile, ]); return $element; } @@ -503,27 +481,38 @@ protected static function hideProfileFields(array &$element, $retain = [], $forc * The element. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state. + * @param ProfileInterface[] $profiles + * The user's profiles * * @return string * The current mode. */ - protected static function getMode(array $element, FormStateInterface $form_state) { + protected static function getMode(array $element, FormStateInterface $form_state, $profiles = []) { $pane_storage = self::getPaneStorage($element, $form_state); - $profile_selection_parents = $element['#parents']; - $profile_selection_parents[] = 'profile_selection'; - $selected_profile = $form_state->getValue($profile_selection_parents); - $mode = 'view'; + $selected_profile = self::getProfileSelectValue($element, $form_state); + + if (is_null($selected_profile) && !empty($element['profile_selection']['#value'])) { + $selected_profile = $element['profile_selection']['#value']; + } + // User is adding a new profile. - if (!empty($selected_profile) && $selected_profile == 'new_profile') { - $mode = 'new'; + if (!empty($selected_profile)) { + $mode = ($selected_profile == 'new_profile') ? 'new' : 'view'; } // If an AJAX rebuild happened, we might have our data in form state. - elseif (!empty($pane_storage['profile'])) { + elseif (!empty($pane_storage['profile']) && !empty($pane_storage['mode'])) { $mode = $pane_storage['mode']; } - elseif (!empty($element['#default_value']) && $element['#default_value'] instanceof ProfileInterface && !$element['#default_value']->id()) { - $mode = 'new'; + // If a new form, either view an existing profile or create a new one. + else { + $mode = (!empty($profiles)) ? 'view' : 'new'; } + + // If no account profiles returned but we're viewing one, edit it instead. + if ($mode == 'view' && empty($profiles)) { + $mode = 'edit'; + } + return $mode; } @@ -551,5 +540,57 @@ protected static function getExistingProfiles(ProfileInterface $default_profile) return $profiles; } -} + /** + * Returns the selected value from the form state, or null if no selection + * has been submitted yet. + * + * @param array $element + * The profile select element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return int|string|NULL + * The selected profile ID, new_profile, or NULL. + */ + protected static function getProfileSelectValue(array $element, FormStateInterface $form_state) { + $values = $form_state->getValues(); + $pane_storage = self::getPaneStorage($element, $form_state); + $parents = $element['#parents']; + $parents[] = 'profile_selection'; + + $selected_value = NULL; + if (NestedArray::keyExists($values, $parents)) { + $selected_value = NestedArray::getValue($values, $parents); + } + elseif (!empty($pane_storage['profile_selection'])) { + $selected_value = $pane_storage['profile_selection']; + } + + return $selected_value; + } + protected static function getDefaultProfile(array $element, FormStateInterface $form_state, $mode, array $profiles) { + $selected_value = self::getProfileSelectValue($element, $form_state); + $pane_storage = self::getPaneStorage($element, $form_state); + $default_profile = $element['#default_value']; + + // If user wants to create a new profile, do so. + if ($selected_value && $mode == 'new') { + $default_profile = \Drupal::entityTypeManager()->getStorage('profile')->create([ + 'type' => $default_profile->bundle(), + 'uid' => $default_profile->getOwnerId(), + ]); + } + // Load profile from form state if it exists. + elseif (!empty($pane_storage['profile'])) { + $default_profile = $pane_storage['profile']; + } + // Select existing user profile if this is a new form. + elseif(!$selected_value && $mode == 'view' && !$default_profile->id()) { + $default_profile = reset($profiles); + } + + return $default_profile; + } + +} From d3c16a2719dc2eaf8cf11a40c5458a759c705930 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Thu, 27 Apr 2017 15:33:14 -0500 Subject: [PATCH 09/10] Refactor profile select element and resolve several AJAX issues --- modules/order/src/Element/ProfileSelect.php | 370 ++++++-------------- 1 file changed, 105 insertions(+), 265 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index ab2bc3e05d..fffd391d9c 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -59,13 +59,14 @@ public function getInfo() { '#reuse_profile_default' => FALSE, // The profile entity operated on. Required. '#default_value' => NULL, + // The profile that to be submitted. Populated automatically. + '#profile' => NULL, + // The operation, 'view', 'add', or 'edit'. Usually populated automatically. + '#op' => NULL, '#process' => [ [$class, 'attachElementSubmit'], [$class, 'processForm'], ], - '#after_build' => [ - [$class, 'afterBuild'], - ], '#element_validate' => [ [$class, 'validateElementSubmit'], [$class, 'validateForm'], @@ -105,28 +106,74 @@ public static function processForm(array $element, FormStateInterface $form_stat throw new \InvalidArgumentException('The commerce_profile_select #available_countries property must be an array.'); } - // Assign a name if it's unset. + // Assign a name if needed. if (empty($element['#name'])) { list($name) = explode('--', $element['#id']); $element['#name'] = 'profile-select--' . $name; } - // Initialize variables. + // Assign shared variables. + $called_class = get_called_class(); + $storage = $form_state->getStorage(); + $pane_storage = isset($storage['pane_' . $element['#name']]) + ? $storage['pane_' . $element['#name']] + : []; + $profile_selection = isset($pane_storage['profile_selection']) + ? $pane_storage['profile_selection'] + : NULL; + $reuse_profile = isset($pane_storage['reuse_profile']) + ? $pane_storage['reuse_profile'] + : $element['#reuse_profile_default']; + + // Define AJAX wrapper $ajax_wrapper_id = Html::getUniqueId('profile-select-ajax-wrapper'); $element['#prefix'] = '
'; $element['#suffix'] = '
'; - $called_class = get_called_class(); - $pane_storage = self::getPaneStorage($element, $form_state); - $profiles = self::getExistingProfiles($element['#default_value']); - $mode = self::getMode($element, $form_state, $profiles); - $default_profile = self::getDefaultProfile($element, $form_state, $mode, $profiles); - $selected_profile = self::getProfileSelectValue($element, $form_state); + + // Load authenticated user's profiles. + $profiles = []; + if ($element['#default_value']->getOwnerId() > 0) { + $profile_ids = \Drupal::service('entity.query') + ->get('profile') + ->condition('uid', $element['#default_value']->getOwnerId()) + ->condition('type', $element['#default_value']->bundle()) + ->condition('status', TRUE) + ->sort('profile_id', 'DESC') + ->execute(); + $profiles = \Drupal::entityTypeManager()->getStorage('profile')->loadMultiple($profile_ids); + } + + // Determine operation to perform. + if (isset($pane_storage['op'])) { + $element['#op'] = $pane_storage['op']; + } + elseif ($profile_selection) { + $element['#op'] = ($profile_selection == 'new_profile') ? 'add' : 'view'; + } + elseif (is_null($element['#op'])) { + $element['#op'] = (!empty($profiles)) ? 'view' : 'add'; + } + // If no account profiles returned but we're viewing one, edit it instead. + if ($element['#op'] === 'view' && empty($profiles)) { + $element['#op'] = 'edit'; + } + + // Determine default profile + $default_profile = $element['#default_value']; + // If user wants to create a new profile, do so. + if ($profile_selection) { + $default_profile = ($profile_selection == 'new_profile') + ? \Drupal::entityTypeManager()->getStorage('profile')->create([ + 'type' => $default_profile->bundle(), + 'uid' => $default_profile->getOwnerId(), + ]) + : $profiles[$profile_selection]; + } + elseif($element['#op'] == 'view' && !$default_profile->id()) { + $default_profile = reset($profiles); + } $element['#default_value'] = $default_profile; $element['#profile'] = $default_profile; - // Set up profile reuse functionality. - $reuse_profile = (isset($pane_storage['reuse_profile'])) - ? $pane_storage['reuse_profile'] - : $element['#reuse_profile_default']; // Set default address field options. $form_display = EntityFormDisplay::collectRenderDisplay($default_profile, 'default'); @@ -136,7 +183,7 @@ public static function processForm(array $element, FormStateInterface $form_stat // Remove the details wrapper from the address widget. $widget_element['#type'] = 'container'; // Provide a default country. - if (!empty($element['#default_country']) && $mode === 'new') { + if (!empty($element['#default_country']) && $element['#op'] === 'add') { $widget_element['address']['#default_value']['country_code'] = $element['#default_country']; } // Limit the available countries. @@ -166,7 +213,7 @@ public static function processForm(array $element, FormStateInterface $form_stat } else { // Output a profile select element. - if ($mode != 'edit' && !empty($profiles)) { + if ($element['#op'] != 'edit' && !empty($profiles)) { $profile_options = []; foreach ($profiles as $profile_option) { $profile_options[$profile_option->id()] = $profile_option->label(); @@ -187,7 +234,7 @@ public static function processForm(array $element, FormStateInterface $form_stat ]; } - if ($mode == 'view') { + if ($element['#op'] == 'view') { $element['rendered_profile'] = [ \Drupal::entityTypeManager() ->getViewBuilder('profile') @@ -196,7 +243,7 @@ public static function processForm(array $element, FormStateInterface $form_stat $element['edit_button'] = [ '#type' => 'button', '#name' => 'pane-' . $element['#name'] . '-edit', - '#value' => t('Edit'), + '#default_value' => t('Edit'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [$called_class, 'profileAjax'], @@ -207,11 +254,11 @@ public static function processForm(array $element, FormStateInterface $form_stat self::hideProfileFields($element, ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile']); } // Editing an existing profile. - elseif (!empty($profiles) && $mode == 'edit') { + elseif (!empty($profiles) && $element['#op'] == 'edit') { $element['cancel_button'] = [ '#type' => 'button', '#name' => 'pane-' . $element['#name'] . '-cancel', - '#value' => t('Cancel and return to profile selection'), + '#default_value' => t('Cancel and select profile'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [$called_class, 'profileAjax'], @@ -223,36 +270,6 @@ public static function processForm(array $element, FormStateInterface $form_stat } } - // Maintain the state of the settings before returning. - self::setPaneStorage($element, $form_state, [ - 'profile' => $default_profile, - 'mode' => $mode, - 'reuse_profile' => $reuse_profile, - 'selected_profile' => $selected_profile, - ]); - return $element; - } - - /** - * Element after_build callback. - * - * @param array $element - * The form element being processed. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The current state of the form. - * - * @return array - * The built form element. - */ - public static function afterBuild(array $element, FormStateInterface $form_state) { - $triggering_element = $form_state->getTriggeringElement(); - if (!empty($triggering_element['#parents'])) { - $last_parent = array_pop($triggering_element['#parents']); - if ($last_parent == 'edit_button') { - $retain = ['edit_button', 'rendered_profile', 'profile_selection', 'reuse_profile']; - self::hideProfileFields($element, $retain, TRUE); - } - } return $element; } @@ -269,10 +286,13 @@ public static function afterBuild(array $element, FormStateInterface $form_state * form, as a protection against buggy behavior. */ public static function validateForm(array &$element, FormStateInterface $form_state) { - $parents = $form_state->getTriggeringElement()['#parents']; - $last_parent = array_pop($parents); - $pane_storage = self::getPaneStorage($element, $form_state); - if (!$pane_storage['reuse_profile'] && !in_array($last_parent, ['edit_button', 'cancel_button'])) { + $triggering_parents = $form_state->getTriggeringElement()['#parents']; + $last_parent = array_pop($triggering_parents); + $storage = $form_state->getStorage(); + $pane_storage = isset($storage['pane_' . $element['#name']]) + ? $storage['pane_' . $element['#name']] + : []; + if ((!isset($pane_storage['reuse_profile']) || !$pane_storage['reuse_profile']) && !in_array($last_parent, ['edit_button', 'cancel_button'])) { $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); $form_display->extractFormValues($element['#profile'], $element, $form_state); $form_display->validateFormValues($element['#profile'], $element, $form_state); @@ -290,19 +310,20 @@ public static function validateForm(array &$element, FormStateInterface $form_st * @throws \Drupal\Core\Entity\EntityStorageException */ public static function submitForm(array &$element, FormStateInterface $form_state) { - $pane_storage = self::getPaneStorage($element, $form_state); - if ($pane_storage['reuse_profile']) { - // Load the current profile by ID or by callback + $storage = $form_state->getStorage(); + if (isset($storage['pane_' . $element['#name']]['reuse_profile']) + && $storage['pane_' . $element['#name']]['reuse_profile']) { + // Load the current profile by ID or by callback. $profile = (is_numeric($element['#reuse_profile_source'])) ? \Drupal::entityTypeManager()->getStorage('profile')->load($element['#reuse_profile_source']) : call_user_func($element['#reuse_profile_source'], $element, $form_state, $form_state->getCompleteForm()); - // There's no valid way to reuse a profile if one is not found. if (!$profile instanceof ProfileInterface) { throw new EntityStorageException('The profile to reuse could not be determined from the provided arguments.'); } $element['#profile'] = $profile; } - elseif (isset($pane_storage['mode']) && in_array($pane_storage['mode'], ['new', 'edit'])) { + elseif (isset($storage['pane_' . $element['#name']]['op']) + && in_array($storage['pane_' . $element['#name']]['op'], ['add', 'edit'])) { $form_display = EntityFormDisplay::collectRenderDisplay($element['#profile'], 'default'); $form_display->extractFormValues($element['#profile'], $element, $form_state); $element['#profile']->save(); @@ -326,7 +347,8 @@ public static function profileAjax(array &$form, FormStateInterface $form_state, $triggering_element = $form_state->getTriggeringElement(); $array_parents = $triggering_element['#array_parents']; array_pop($array_parents); - return NestedArray::getValue($form, $array_parents); + $profile_form = NestedArray::getValue($form, $array_parents); + return $profile_form; } /** @@ -339,10 +361,12 @@ public static function profileAjax(array &$form, FormStateInterface $form_state, */ public static function profileReuseValidate(array $element, FormStateInterface $form_state) { $form = $form_state->getCompleteForm(); - $profile_element_parents = $element['#parents']; - array_pop($profile_element_parents); - $profile_element = NestedArray::getValue($form, $profile_element_parents); - self::setPaneStorage($profile_element, $form_state, 'reuse_profile', $element['#value']); + $parents = $element['#array_parents']; + array_pop($parents); + $storage = $form_state->getStorage(); + $profile_form = NestedArray::getValue($form, $parents); + $storage['pane_' . $profile_form['#name']]['reuse_profile'] = $element['#value']; + $form_state->setStorage($storage); } /** @@ -354,30 +378,16 @@ public static function profileReuseValidate(array $element, FormStateInterface $ * The current state of the form. */ public static function profileSelectValidate(array $element, FormStateInterface $form_state) { - $triggering_element = $form_state->getTriggeringElement(); - if (in_array('profile_selection', $triggering_element['#array_parents']) && $triggering_element['#id'] == $element['#id']) { - $form = $form_state->getCompleteForm(); - $profile_element_parents = $element['#parents']; - array_pop($profile_element_parents); - $profile_element = NestedArray::getValue($form, $profile_element_parents); - $pane_storage = self::getPaneStorage($profile_element, $form_state); - $profile_storage = \Drupal::entityTypeManager()->getStorage('profile'); - $create_profile = ($element['#value'] == 'new_profile'); - if ($create_profile) { - /** @var ProfileInterface $existing_profile */ - $existing_profile = $profile_element['#profile']; - $profile = $profile_storage->create([ - 'type' => $existing_profile->bundle(), - 'uid' => $existing_profile->getOwnerId(), - ]); - } else { - $profile_id = $form_state->getValue($element['#parents']); - $profile = $profile_storage->load($profile_id); - } - $pane_storage['profile'] = $profile; - $pane_storage['mode'] = $create_profile ? 'new' : 'view'; - self::setPaneStorage($profile_element, $form_state, $pane_storage); + $form = $form_state->getCompleteForm(); + $parents = $element['#array_parents']; + array_pop($parents); + $storage = $form_state->getStorage(); + $profile_form = NestedArray::getValue($form, $parents); + $storage['pane_' . $profile_form['#name']]['profile_selection'] = $element['#value']; + if (isset($storage['pane_' . $profile_form['#name']]['op']) && $storage['pane_' . $profile_form['#name']]['op'] != 'edit') { + $storage['pane_' . $profile_form['#name']]['op'] = $element['#value'] == 'new_profile' ? 'add' : 'view'; } + $form_state->setStorage($storage); } /** @@ -391,69 +401,18 @@ public static function profileSelectValidate(array $element, FormStateInterface public static function profileEditCancelValidate(array $element, FormStateInterface $form_state) { $triggering_element = $form_state->getTriggeringElement(); if ($triggering_element && $triggering_element['#id'] === $element['#id']) { - $array_parents = $triggering_element['#array_parents']; - $last_parent = array_pop($array_parents); + $parents = $triggering_element['#array_parents']; + $last_parent = array_pop($parents); if (in_array($last_parent, ['edit_button', 'cancel_button'])) { - $complete_form = $form_state->getCompleteForm(); - $parents = $element['#parents']; - array_pop($parents); - $profile_element = NestedArray::getValue($complete_form, $parents); - $mode = ($last_parent == 'edit_button') ? 'edit' : 'view'; - self::setPaneStorage($profile_element, $form_state, 'mode', $mode); + $form = $form_state->getCompleteForm(); + $profile_form = NestedArray::getValue($form, $parents); + $storage = $form_state->getStorage(); + $storage['pane_' . $profile_form['#name']]['op'] = ($last_parent == 'edit_button') ? 'edit' : 'view'; + $form_state->setStorage($storage); } } } - /** - * Get the current pane storage values from the form state, or the defaults. - * - * @param array $element - * The element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state. - * - * @return array - * The pane storage array. - */ - protected static function getPaneStorage(array &$element, FormStateInterface $form_state) { - $storage = $form_state->getStorage(); - $pane_storage = isset($storage['pane_' . $element['#name']]) - ? $storage['pane_' . $element['#name']] - : []; - $defaults = [ - 'profile' => NULL, - 'reuse_profile' => NULL, - 'mode' => 'view' - ]; - return $pane_storage + $defaults; - } - - /** - * Stores one or all values to the pane storage. - * - * @param array $element - * The element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state. - * @param $keyOrValues - * Either the key to set, or an array to replace the entire pane storage - * with. - * @param null $value - * The new value to set if setting a single key. Used only if $keyOrValue - * is not an array. - */ - protected static function setPaneStorage(array &$element, FormStateInterface $form_state, $keyOrValues, $value = NULL) { - if (is_array($keyOrValues)) { - $pane_storage = $keyOrValues; - } else { - $pane_storage = self::getPaneStorage($element, $form_state); - $pane_storage[$keyOrValues] = $value; - } - $storage = $form_state->getStorage(); - $storage['pane_' . $element['#name']] = $pane_storage; - $form_state->setStorage($storage); - } - /** * Hides fields from the element which should not be visible. * @@ -474,123 +433,4 @@ protected static function hideProfileFields(array &$element, $retain = [], $forc } } - /** - * Get the current mode of the profile select element. - * - * @param array $element - * The element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state. - * @param ProfileInterface[] $profiles - * The user's profiles - * - * @return string - * The current mode. - */ - protected static function getMode(array $element, FormStateInterface $form_state, $profiles = []) { - $pane_storage = self::getPaneStorage($element, $form_state); - $selected_profile = self::getProfileSelectValue($element, $form_state); - - if (is_null($selected_profile) && !empty($element['profile_selection']['#value'])) { - $selected_profile = $element['profile_selection']['#value']; - } - - // User is adding a new profile. - if (!empty($selected_profile)) { - $mode = ($selected_profile == 'new_profile') ? 'new' : 'view'; - } - // If an AJAX rebuild happened, we might have our data in form state. - elseif (!empty($pane_storage['profile']) && !empty($pane_storage['mode'])) { - $mode = $pane_storage['mode']; - } - // If a new form, either view an existing profile or create a new one. - else { - $mode = (!empty($profiles)) ? 'view' : 'new'; - } - - // If no account profiles returned but we're viewing one, edit it instead. - if ($mode == 'view' && empty($profiles)) { - $mode = 'edit'; - } - - return $mode; - } - - /** - * Loads the current user's profiles. - * - * @param ProfileInterface $default_profile - * The default profile for the element. - * - * @return ProfileInterface[] - * The profiles. - */ - protected static function getExistingProfiles(ProfileInterface $default_profile) { - $profiles = []; - if ($default_profile->getOwnerId() > 0) { - $profile_ids = \Drupal::service('entity.query') - ->get('profile') - ->condition('uid', $default_profile->getOwnerId()) - ->condition('type', $default_profile->bundle()) - ->condition('status', TRUE) - ->sort('profile_id', 'DESC') - ->execute(); - $profiles = \Drupal::entityTypeManager()->getStorage('profile')->loadMultiple($profile_ids); - } - return $profiles; - } - - /** - * Returns the selected value from the form state, or null if no selection - * has been submitted yet. - * - * @param array $element - * The profile select element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state. - * - * @return int|string|NULL - * The selected profile ID, new_profile, or NULL. - */ - protected static function getProfileSelectValue(array $element, FormStateInterface $form_state) { - $values = $form_state->getValues(); - $pane_storage = self::getPaneStorage($element, $form_state); - $parents = $element['#parents']; - $parents[] = 'profile_selection'; - - $selected_value = NULL; - if (NestedArray::keyExists($values, $parents)) { - $selected_value = NestedArray::getValue($values, $parents); - } - elseif (!empty($pane_storage['profile_selection'])) { - $selected_value = $pane_storage['profile_selection']; - } - - return $selected_value; - } - - protected static function getDefaultProfile(array $element, FormStateInterface $form_state, $mode, array $profiles) { - $selected_value = self::getProfileSelectValue($element, $form_state); - $pane_storage = self::getPaneStorage($element, $form_state); - $default_profile = $element['#default_value']; - - // If user wants to create a new profile, do so. - if ($selected_value && $mode == 'new') { - $default_profile = \Drupal::entityTypeManager()->getStorage('profile')->create([ - 'type' => $default_profile->bundle(), - 'uid' => $default_profile->getOwnerId(), - ]); - } - // Load profile from form state if it exists. - elseif (!empty($pane_storage['profile'])) { - $default_profile = $pane_storage['profile']; - } - // Select existing user profile if this is a new form. - elseif(!$selected_value && $mode == 'view' && !$default_profile->id()) { - $default_profile = reset($profiles); - } - - return $default_profile; - } - } From 0b7d6bd56d6de9b3d1082046978eb140fe514ee4 Mon Sep 17 00:00:00 2001 From: Ben McClure Date: Thu, 27 Apr 2017 22:53:35 -0500 Subject: [PATCH 10/10] Change #default_value to #value on buttons --- modules/order/src/Element/ProfileSelect.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/order/src/Element/ProfileSelect.php b/modules/order/src/Element/ProfileSelect.php index fffd391d9c..707a0974f0 100644 --- a/modules/order/src/Element/ProfileSelect.php +++ b/modules/order/src/Element/ProfileSelect.php @@ -243,7 +243,7 @@ public static function processForm(array $element, FormStateInterface $form_stat $element['edit_button'] = [ '#type' => 'button', '#name' => 'pane-' . $element['#name'] . '-edit', - '#default_value' => t('Edit'), + '#value' => t('Edit'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [$called_class, 'profileAjax'], @@ -258,7 +258,7 @@ public static function processForm(array $element, FormStateInterface $form_stat $element['cancel_button'] = [ '#type' => 'button', '#name' => 'pane-' . $element['#name'] . '-cancel', - '#default_value' => t('Cancel and select profile'), + '#value' => t('Cancel and select profile'), '#limit_validation_errors' => [], '#ajax' => [ 'callback' => [$called_class, 'profileAjax'],