View source
<?php
namespace Drupal\commerce_product\Form;
use Drupal\commerce\EntityHelper;
use Drupal\commerce\InlineFormManager;
use Drupal\commerce_product\ProductAttributeFieldManagerInterface;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\BundleEntityFormBase;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ProductAttributeForm extends BundleEntityFormBase {
protected $attributeFieldManager;
protected $inlineFormManager;
public function __construct(ProductAttributeFieldManagerInterface $attribute_field_manager, InlineFormManager $inline_form_manager) {
$this->attributeFieldManager = $attribute_field_manager;
$this->inlineFormManager = $inline_form_manager;
}
public static function create(ContainerInterface $container) {
return new static($container
->get('commerce_product.attribute_field_manager'), $container
->get('plugin.manager.commerce_inline_form'));
}
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$attribute = $this->entity;
$form['label'] = [
'#type' => 'textfield',
'#title' => $this
->t('Name'),
'#maxlength' => 255,
'#default_value' => $attribute
->label(),
'#required' => TRUE,
];
$form['id'] = [
'#type' => 'machine_name',
'#default_value' => $attribute
->id(),
'#machine_name' => [
'exists' => '\\Drupal\\commerce_product\\Entity\\ProductAttribute::load',
],
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH - 10,
'#disabled' => !$attribute
->isNew(),
];
$form['elementType'] = [
'#type' => 'select',
'#title' => $this
->t('Element type'),
'#description' => $this
->t('Controls how the attribute is displayed on the add to cart form.'),
'#options' => [
'radios' => $this
->t('Radio buttons'),
'select' => $this
->t('Select list'),
'commerce_product_rendered_attribute' => $this
->t('Rendered attribute'),
],
'#default_value' => $attribute
->getElementType(),
];
$attribute_field_map = $this->attributeFieldManager
->getFieldMap();
$variation_type_storage = $this->entityTypeManager
->getStorage('commerce_product_variation_type');
$variation_types = $variation_type_storage
->loadMultiple();
$form['original_variation_types'] = [
'#type' => 'value',
'#value' => [],
];
$form['variation_types'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Product variation types'),
'#options' => EntityHelper::extractLabels($variation_types),
'#access' => count($variation_types) > 0,
];
$disabled_variation_types = [];
foreach ($variation_types as $variation_type_id => $variation_type) {
if (!$attribute
->isNew() && isset($attribute_field_map[$variation_type_id])) {
$used_attributes = array_column($attribute_field_map[$variation_type_id], 'attribute_id');
if (in_array($attribute
->id(), $used_attributes)) {
$form['original_variation_types']['#value'][$variation_type_id] = $variation_type_id;
$form['variation_types']['#default_value'][$variation_type_id] = $variation_type_id;
if (!$this->attributeFieldManager
->canDeleteField($attribute, $variation_type_id)) {
$form['variation_types'][$variation_type_id] = [
'#disabled' => TRUE,
];
$disabled_variation_types[] = $variation_type_id;
}
}
}
}
$form['disabled_variation_types'] = [
'#type' => 'value',
'#value' => $disabled_variation_types,
];
if ($this->moduleHandler
->moduleExists('content_translation')) {
$enabled = TRUE;
if (!$attribute
->isNew()) {
$translation_manager = \Drupal::service('content_translation.manager');
$enabled = $translation_manager
->isEnabled('commerce_product_attribute_value', $attribute
->id());
}
$form['enable_value_translation'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable attribute value translation'),
'#default_value' => $enabled,
];
}
if (!$attribute
->isNew()) {
$form = $this
->buildValuesForm($form, $form_state);
}
return $form;
}
public function buildValuesForm(array $form, FormStateInterface $form_state) {
$attribute = $this->entity;
$values = $attribute
->getValues();
$user_input = $form_state
->getUserInput();
if ($form_state
->get('reset_alphabetical')) {
$value_names = EntityHelper::extractLabels($values);
asort($value_names);
foreach (array_keys($value_names) as $weight => $id) {
$values[$id]
->setWeight($weight);
}
}
$value_map = (array) $form_state
->get('value_map');
if (empty($value_map)) {
$value_map = $values ? array_keys($values) : [
'_new',
];
$form_state
->set('value_map', $value_map);
}
$wrapper_id = Html::getUniqueId('product-attribute-values-ajax-wrapper');
$form['values'] = [
'#type' => 'table',
'#header' => [
[
'data' => $this
->t('Value'),
'colspan' => 2,
],
$this
->t('Weight'),
$this
->t('Operations'),
],
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'product-attribute-value-order-weight',
],
],
'#weight' => 5,
'#prefix' => '<div id="' . $wrapper_id . '">',
'#suffix' => '</div>',
'#input' => FALSE,
];
$max_weight = count($value_map);
foreach ($value_map as $index => $id) {
$value_form =& $form['values'][$index];
$value_form['#attributes']['class'][] = 'draggable';
$value_form['tabledrag'] = [
'#markup' => '',
];
if ($id == '_new') {
$value = $this->entityTypeManager
->getStorage('commerce_product_attribute_value')
->create([
'attribute' => $attribute
->id(),
'langcode' => $attribute
->get('langcode'),
]);
$default_weight = $max_weight;
$remove_access = TRUE;
}
else {
$value = $values[$id];
$default_weight = $value
->getWeight();
$remove_access = $value
->access('delete');
}
$inline_form = $this->inlineFormManager
->createInstance('content_entity', [
'skip_save' => TRUE,
], $value);
$value_form['entity'] = [
'#parents' => [
'values',
$index,
'entity',
],
'#inline_form' => $inline_form,
];
$value_form['entity'] = $inline_form
->buildInlineForm($value_form['entity'], $form_state);
$value_form['weight'] = [
'#type' => 'weight',
'#title' => $this
->t('Weight'),
'#title_display' => 'invisible',
'#delta' => $max_weight,
'#default_value' => $default_weight,
'#attributes' => [
'class' => [
'product-attribute-value-order-weight',
],
],
];
if (isset($user_input['values'][$index])) {
$input_weight = $user_input['values'][$index]['weight'];
if ($form_state
->get('reset_alphabetical')) {
$input_weight = $default_weight;
}
if ($user_input['values'][$index]['weight'] > $max_weight) {
$input_weight = $max_weight;
}
$value_form['weight']['#value'] = $input_weight;
$value_form['#weight'] = $input_weight;
}
else {
$value_form['#weight'] = $default_weight;
}
$value_form['remove'] = [
'#type' => 'submit',
'#name' => 'remove_value' . $index,
'#value' => $this
->t('Remove'),
'#limit_validation_errors' => [],
'#submit' => [
'::removeValueSubmit',
],
'#value_index' => $index,
'#ajax' => [
'callback' => '::valuesAjax',
'wrapper' => $wrapper_id,
],
'#access' => $remove_access,
];
}
uasort($form['values'], [
'\\Drupal\\Component\\Utility\\SortArray',
'sortByWeightProperty',
]);
$access_handler = $this->entityTypeManager
->getAccessControlHandler('commerce_product_attribute_value');
if ($access_handler
->createAccess($attribute
->id())) {
$form['values']['_add_new'] = [
'#tree' => FALSE,
];
$form['values']['_add_new']['entity'] = [
'#type' => 'container',
'#wrapper_attributes' => [
'colspan' => 2,
],
];
$form['values']['_add_new']['entity']['add_value'] = [
'#type' => 'submit',
'#value' => $this
->t('Add value'),
'#submit' => [
'::addValueSubmit',
],
'#limit_validation_errors' => [],
'#ajax' => [
'callback' => '::valuesAjax',
'wrapper' => $wrapper_id,
],
];
$form['values']['_add_new']['entity']['reset_alphabetical'] = [
'#type' => 'submit',
'#value' => $this
->t('Reset to alphabetical'),
'#submit' => [
'::resetAlphabeticalSubmit',
],
'#limit_validation_errors' => [],
'#ajax' => [
'callback' => '::valuesAjax',
'wrapper' => $wrapper_id,
],
];
$form['values']['_add_new']['operations'] = [
'data' => [],
];
}
return $form;
}
public function valuesAjax(array $form, FormStateInterface $form_state) {
return $form['values'];
}
public function addValueSubmit(array $form, FormStateInterface $form_state) {
$value_map = (array) $form_state
->get('value_map');
$value_map[] = '_new';
$form_state
->set('value_map', $value_map);
$form_state
->setRebuild();
}
public function resetAlphabeticalSubmit(array $form, FormStateInterface $form_state) {
$form_state
->set('reset_alphabetical', TRUE);
$form_state
->setRebuild();
}
public function removeValueSubmit(array $form, FormStateInterface $form_state) {
$value_index = $form_state
->getTriggeringElement()['#value_index'];
$value_map = (array) $form_state
->get('value_map');
$value_id = $value_map[$value_index];
unset($value_map[$value_index]);
$form_state
->set('value_map', $value_map);
if ($value_id != '_new') {
$delete_queue = (array) $form_state
->get('delete_queue');
$delete_queue[] = $value_id;
$form_state
->set('delete_queue', $delete_queue);
}
$form_state
->setRebuild();
}
protected function saveValues(array $form, FormStateInterface $form_state) {
$delete_queue = $form_state
->get('delete_queue');
if (!empty($delete_queue)) {
$value_storage = $this->entityTypeManager
->getStorage('commerce_product_attribute_value');
$values = $value_storage
->loadMultiple($delete_queue);
$value_storage
->delete($values);
}
foreach ($form_state
->getValue([
'values',
]) as $index => $value_data) {
$inline_form = $form['values'][$index]['entity']['#inline_form'];
$value = $inline_form
->getEntity();
$value
->setWeight($value_data['weight']);
$value
->save();
}
}
public function save(array $form, FormStateInterface $form_state) {
$status = $this->entity
->save();
$original_variation_types = $form_state
->getValue('original_variation_types', []);
$variation_types = array_filter($form_state
->getValue('variation_types', []));
$disabled_variation_types = $form_state
->getValue('disabled_variation_types', []);
$variation_types = array_unique(array_merge($disabled_variation_types, $variation_types));
$selected_variation_types = array_diff($variation_types, $original_variation_types);
$unselected_variation_types = array_diff($original_variation_types, $variation_types);
if ($selected_variation_types) {
foreach ($selected_variation_types as $selected_variation_type) {
$this->attributeFieldManager
->createField($this->entity, $selected_variation_type);
}
}
if ($unselected_variation_types) {
foreach ($unselected_variation_types as $unselected_variation_type) {
$this->attributeFieldManager
->deleteField($this->entity, $unselected_variation_type);
}
}
if ($this->moduleHandler
->moduleExists('content_translation')) {
$translation_manager = \Drupal::service('content_translation.manager');
$enabled = $form_state
->getValue('enable_value_translation');
if ($translation_manager
->isEnabled('commerce_product_attribute_value', $this->entity
->id()) != $enabled) {
$translation_manager
->setEnabled('commerce_product_attribute_value', $this->entity
->id(), $enabled);
$this->entityTypeManager
->clearCachedDefinitions();
\Drupal::service('router.builder')
->setRebuildNeeded();
}
}
if ($status == SAVED_NEW) {
$this
->messenger()
->addMessage($this
->t('Created the %label product attribute.', [
'%label' => $this->entity
->label(),
]));
$form_state
->setRedirectUrl($this->entity
->toUrl('edit-form'));
}
else {
$this
->saveValues($form, $form_state);
$this
->messenger()
->addMessage($this
->t('Updated the %label product attribute.', [
'%label' => $this->entity
->label(),
]));
$form_state
->setRedirectUrl($this->entity
->toUrl('collection'));
}
}
}