diff --git a/modules/product/src/Form/ProductVariationTypeForm.php b/modules/product/src/Form/ProductVariationTypeForm.php index 95ee472..d7bedbb 100644 --- a/modules/product/src/Form/ProductVariationTypeForm.php +++ b/modules/product/src/Form/ProductVariationTypeForm.php @@ -2,14 +2,42 @@ namespace Drupal\commerce_product\Form; +use Drupal\commerce_product\ProductAttributeFieldManagerInterface; use Drupal\Core\Entity\BundleEntityFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\language\Entity\ContentLanguageSettings; +use Symfony\Component\DependencyInjection\ContainerInterface; class ProductVariationTypeForm extends BundleEntityFormBase { /** + * The attribute field manager. + * + * @var \Drupal\commerce_product\ProductAttributeFieldManagerInterface + */ + protected $attributeFieldManager; + + /** + * Constructs a new ProductVariationTypeForm object. + * + * @param \Drupal\commerce_product\ProductAttributeFieldManagerInterface $attribute_field_manager + * The attribute field manager. + */ + public function __construct(ProductAttributeFieldManagerInterface $attribute_field_manager) { + $this->attributeFieldManager = $attribute_field_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('commerce_product.attribute_field_manager') + ); + } + + /** * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { @@ -59,6 +87,44 @@ class ProductVariationTypeForm extends BundleEntityFormBase { ]; } + if (!$variation_type->isNew()) { + /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface[] $attributes */ + $attributes = $this->entityTypeManager->getStorage('commerce_product_attribute')->loadMultiple(); + $attribute_options = array_map(function ($attribute) { + /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface $attribute */ + return $attribute->label(); + }, $attributes); + $attribute_map = $this->attributeFieldManager->getFieldMap($variation_type->id()); + $used_attributes = array_column($attribute_map, 'attribute_id'); + + $immutable_options = []; + if (!empty($used_attributes)) { + // Discover what options cannot be unset. + foreach ($attributes as $attribute) { + if (!$this->attributeFieldManager->canDeleteField($attribute)) { + $immutable_options[] = $attribute; + } + } + } + + $form['original_attributes'] = [ + '#type' => 'value', + '#value' => $used_attributes, + ]; + $form['attributes'] = [ + '#type' => 'checkboxes', + '#title' => t('Attributes'), + '#options' => $attribute_options, + '#default_value' => $used_attributes, + ]; + + foreach ($immutable_options as $key => $immutable_option) { + $form['attributes'][$immutable_option->id()] = [ + '#disabled' => TRUE, + ]; + } + } + if ($this->moduleHandler->moduleExists('language')) { $form['language'] = [ '#type' => 'details', @@ -82,10 +148,62 @@ class ProductVariationTypeForm extends BundleEntityFormBase { /** * {@inheritdoc} */ + public function validateForm(array &$form, FormStateInterface $form_state) { + parent::validateForm($form, $form_state); + + $attribute_storage = $this->entityTypeManager->getStorage('commerce_product_attribute'); + $original_attributes = $form_state->getValue('original_attributes'); + $attributes = array_filter($form_state->getValue('attributes')); + $unselected_attributes = array_diff($original_attributes, $attributes); + if ($unselected_attributes) { + /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface[] $unselected_attributes */ + $unselected_attributes = $attribute_storage->loadMultiple($unselected_attributes); + foreach ($unselected_attributes as $attribute) { + if (!$this->attributeFieldManager->canDeleteField($attribute)) { + $form_state->setErrorByName('attributes', t("The @label attribute can't be removed because it has data.", ['@label' => $attribute->label()])); + break; + } + } + } + } + + /** + * {@inheritdoc} + */ public function save(array $form, FormStateInterface $form_state) { - $this->entity->save(); - drupal_set_message($this->t('The product variation type %label has been successfully saved.', ['%label' => $this->entity->label()])); - $form_state->setRedirect('entity.commerce_product_variation_type.collection'); + if (!$this->entity->isNew()) { + $attribute_storage = $this->entityTypeManager->getStorage('commerce_product_attribute'); + $original_attributes = $form_state->getValue('original_attributes'); + $attributes = array_filter($form_state->getValue('attributes')); + $selected_attributes = array_diff($attributes, $original_attributes); + $unselected_attributes = array_diff($original_attributes, $attributes); + if ($selected_attributes) { + /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface[] $selected_attributes */ + $selected_attributes = $attribute_storage->loadMultiple($selected_attributes); + foreach ($selected_attributes as $attribute) { + $this->attributeFieldManager->createField($attribute, $this->entity->id()); + } + } + if ($unselected_attributes) { + /** @var \Drupal\commerce_product\Entity\ProductAttributeInterface[] $unselected_attributes */ + $unselected_attributes = $attribute_storage->loadMultiple($unselected_attributes); + foreach ($unselected_attributes as $attribute) { + $this->attributeFieldManager->deleteField($attribute, $this->entity->id()); + } + } + } + + $status = $this->entity->save(); + drupal_set_message($this->t('Saved the %label product variation type.', ['%label' => $this->entity->label()])); + if ($status == SAVED_UPDATED) { + $form_state->setRedirect('entity.commerce_product_variation_type.collection'); + } + elseif ($status == SAVED_NEW) { + // Send the user to the Edit form to see the Attributes element. + $form_state->setRedirect('entity.commerce_product_variation_type.edit_form', [ + 'commerce_product_variation_type' => $this->entity->id(), + ]); + } } }