It would be great if we coud have different form view modes since we are using the same bundle both for billing and shipping in commerce_shipping. That way we could display certain fields only on one customer profile but not the others.

My current use case is a phone number required by some shipping providers. I want it to be required and only displayed in the shipping profile.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Lukas von Blarer created an issue. See original summary.

Lukas von Blarer’s picture

As a temporary workaround i used the hook_entity_form_display_alter hook:

<?php
function hook_entity_form_display_alter(\Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display, array $context) {
  if ($context['entity_type'] == 'profile') {
    $route_name = \Drupal::routeMatch()->getRouteName();
    $route_parameter = \Drupal::routeMatch()->getParameter('step');
    if($route_name == 'commerce_checkout.form' && $route_parameter == 'payment_information') {
      $form_display->removeComponent('field_phone');^
    }
  }
}
?>
MegaChriz’s picture

I need to have different form modes for the commerce_profile_select element as well. In \Drupal\commerce_order\Element\ProfileSelect, the form mode to use for display is hard-coded.

It would be great if you can specify the form mode on the element itself. That could be done like this:

$pane_form['profile'] = [
  '#type' => 'commerce_profile_select',
  '#default_value' => $profile,
  '#form_mode' => 'checkout',
];

The attached patch adds a property called '#form_mode' on the commerce_profile_select element.

Note: this patch would probably need to be rerolled when #2844920: Allow customer profiles to be reused lands.

bojanz’s picture

This feature would make it impossible to implement the "My billing information is the same as my shipping information" checkbox with confidence, because we'd never be able to guarantee that the profile we're copying from has all of the required fields filled in.

For example, a VAT Number field that is shown only on the billing info. Then, the shipping info is used. We now have a profile selected without the required information. Or, the OP's phone example, if shipping and billing swap places in a custom checkout flow.

Fields that are shipping specific can live on the shipment.

MegaChriz’s picture

@bojanz
My use case is: show a different set of fields on checkout and an other set at my account (user/x/customer, profile/x/edit). In my custom implementation, the billing and shipping panes use the same form mode. From my perspective it makes more sense that the default form mode is used at profile/x/edit and the "checkout" form mode (which what I called it) at checkout.

Maybe this should be a separate issue? As my use case is a bit different compared to the one from the issue starter.

MegaChriz’s picture

Re-implementation of the patch in #3. The code is now targeting Drupal\commerce_order\Plugin\Commerce\InlineForm\CustomerProfile instead, as the "commerce_profile_select" form element is deprecated since Commerce 8.x-2.12.

In my custom code I'm using the inline profile form like this:

// Main profile.
$inline_form = $this->inlineFormManager->createInstance('customer_profile', [
  'form_mode' => 'checkout',
], $person_profile);
$pane_form['profile'] = [
  '#type' => 'container',
  '#parents' => array_merge($pane_form['#parents'], ['profile']),
  '#inline_form' => $inline_form,
];
$pane_form['profile'] = $inline_form->buildInlineForm($pane_form['profile'], $form_state);

// Company info.
$inline_form = $this->inlineFormManager->createInstance('customer_profile', [
  'form_mode' => 'checkout',
], $company_profile);
$pane_form['company'] = [
  '#type' => 'container',
  '#parents' => array_merge($pane_form['#parents'], ['company']),
  '#inline_form' => $inline_form,
  '#states' => [
    'visible' => [
      ':input[name="ukkb_commerce_contact_information[company_name]"]' => ['filled' => TRUE],
    ],
  ],
];
$pane_form['company'] = $inline_form->buildInlineForm($pane_form['company'], $form_state);

So in my case I'm not specifically targeting the billing/shipping profiles, but other profile types ('person' and 'company' in this case).
(The addition of '#type' => 'container' is needed to work around core bug #2700667: Notice: Undefined index: #type in Drupal\Core\Form\FormHelper::processStates() )

bojanz’s picture

Title: Add form separate view modes for customer profiles » [Addressbook part 4] Use separate form modes for each customer profile
Status: Needs review » Needs work

Retitling, adding to general effort. Unsure if we also need matching view modes.

#3022850: [Addressbook, part 1] Rework the ownership model for customer profiles is adding an #instance_id to each customer profile, to be used by #2910193: Allow reusing profile values from another inline form ("Billing same as shipping"). We could pass that along as the form mode, since core falls back to "default" automatically. That would give us "billing" and "shipping" form modes and displays, for example. We'd also want to add the exported config for the form mode & display, as well as an update hook.

I no longer think #4 is a problem, we can get around that. How depends on the chosen UX in #3053165: [Addressbook part 2] Complete the UI by allowing choice between multiple addressbook profiles

mindaugasd’s picture

Unsure if we also need matching view modes.

My guess is:

  • Viewmodes are place specific and not "profile-type" specific per say.
  • There are different places: checkout panes, user profile, order views, emails, invoices...
  • So if viewmode can be chosen for specific place, so it can be chosen in "profile-type" use case as well at the same time.
MegaChriz’s picture

Status: Needs work » Needs review
FileSize
1.83 KB

Unsure if we also need matching view modes.

In my setup, I've only defined "checkout" as a form mode, not a view mode. So in my opinion we shouldn't have a setting where we assume that $form_mode == $view_mode. So not matching view modes. Since CustomerProfile now can build the view of the profile too (see code snippet below), I agree that it makes sense to add a setting for view mode as well.

The attached patch now adds settings for both form mode and view mode. It's also a sort of reroll, since the patch in #6 no longer applies. There are apparently less occurrences of EntityFormDisplay::collectRenderDisplay() now in CustomerProfile.

$view_builder = $this->entityTypeManager->getViewBuilder('profile');
$inline_form['rendered'] = $view_builder->view($this->entity);

CustomerProfile can build the view for the profile entity now.

bojanz’s picture

Title: [Addressbook part 4] Use separate form modes for each customer profile » Use separate form modes for each customer profile

Removing from the address book effort, since this won't be done for the 2.14 release.

People can use hook_commerce_inline_form_customer_profile_alter() as a workaround (with access to both the profile form and the rendered profile).

MegaChriz’s picture

View mode

Ah, I see. So for setting a view mode, you could now do the following:

/**
 * Implements hook_commerce_inline_form_PLUGIN_ID_alter() for 'customer_profile'.
 */
function mymodule_commerce_inline_form_customer_profile_alter(array &$inline_form, FormStateInterface $form_state, array &$complete_form) {
  if (isset($inline_form['rendered'])) {
    $inline_form['rendered']['#view_mode'] = 'my_view_mode';
  }
}

Form mode

Altering the form mode this way would be a little harder, I think. When this hook is invoked, the form using the default form display has already been built. And the form display is loaded in ::buildInlineForm(), ::validateInlineForm() and ::submitInlineForm(). So I guess this means that you would need to override #validate and #submit handlers to pass in the desired form display if you want to use the hook to alter things.

An other option would be extending CustomerProfile and overriding ::loadFormDisplay() in there. You can alter plugin classes by implementing hook_commerce_inline_form_info_alter():

in mymodule.module:

use Drupal\mymodule\Plugin\Commerce\InlineForm\CustomerProfile;

/**
 * Implements hook_commerce_inline_form_info_alter().
 *
 * Overrides class for "customer_profile" plugin.
 */
function mymodule_commerce_inline_form_info_alter(array &$inline_forms) {
  if (isset($inline_forms['customer_profile'])) {
    $inline_forms['customer_profile']['class'] = CustomerProfile::class;
  }
}

in src/mymodule/Plugin/Commerce/InlineForm/CustomerProfile.php:


namespace Drupal\mymodule\Plugin\Commerce\InlineForm;

use Drupal\commerce_order\Plugin\Commerce\InlineForm\CustomerProfile as CustomerProfileBase;
use Drupal\Core\Entity\Entity\EntityFormDisplay;

/**
 * {@inheritdoc}
 */
class CustomerProfile extends CustomerProfileBase {

  /**
   * {@inheritdoc}
   */
  protected function loadFormDisplay() {
    $form_display = EntityFormDisplay::collectRenderDisplay($this->entity, 'my_form_mode');
    // The log message field should never be shown to customers.
    $form_display->removeComponent('revision_log_message');

    return $form_display;
  }

}
bojanz’s picture

Assigned: Unassigned » bojanz

Scheduling this for 2.17.

bojanz’s picture

Here we go. Intentionally not creating a matching form display for BC reasons, to allow people to continue using the same (default) form display for both billing and shipping if they wish.

Doing the shipping side in #3114293: Add a "shipping" profile form mode.

This cleanup will also allow tax_number fields to be handled properly by "Billing same as shipping". We can't hide fields in the inline form alter hook, that must be done on the form display level.

Note that I'm not making the form modes configurable because "Billing same as shipping" needs to be able know which form modes are used. Handling all of that can be a potential followup.

bojanz’s picture

Status: Needs review » Needs work

The last submitted patch, 14: 2917102-14-customer-profile-form-mode.patch, failed testing. View results

bojanz’s picture

The config file was breaking uninstall due to a missing dependency.

Third time's the charm.

EDIT: Aaand no clue how the shipping patch got there.

bojanz’s picture

Status: Needs review » Fixed

Committed 2917102-15-customer-profile-form-mode.patch.

  • bojanz committed 6772b6d on 8.x-2.x
    Issue #2917102 by MegaChriz, bojanz: Use separate form modes for each...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.