View source
<?php
namespace Drupal\entityqueue\Plugin\Field\FieldWidget;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\Plugin\Validation\Constraint\ValidReferenceConstraint;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Field\FieldFilteredMarkup;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldWidget\EntityReferenceAutocompleteWidget;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Symfony\Component\Validator\ConstraintViolationInterface;
class EntityqueueDragtableWidget extends EntityReferenceAutocompleteWidget {
protected $wrapperId;
public static function defaultSettings() {
return [
'link_to_entity' => FALSE,
'link_to_edit_form' => TRUE,
] + parent::defaultSettings();
}
public function settingsForm(array $form, FormStateInterface $form_state) {
$elements = parent::settingsForm($form, $form_state);
$elements['link_to_entity'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Link label to the referenced entity'),
'#default_value' => $this
->getSetting('link_to_entity'),
];
$elements['link_to_edit_form'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Add a link to the edit form of the referenced entity'),
'#default_value' => $this
->getSetting('link_to_edit_form'),
];
return $elements;
}
public function settingsSummary() {
$summary = parent::settingsSummary();
$settings = $this
->getSettings();
if (!empty($settings['link_to_entity'])) {
$summary[] = $this
->t('Link to the referenced entity');
}
if (!empty($settings['link_to_edit_form'])) {
$summary[] = $this
->t('Link to the edit form of the referenced entity');
}
return $summary;
}
public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) {
if ($this->fieldDefinition
->getTargetEntityTypeId() === 'entity_subqueue' && $this->fieldDefinition
->getName() === 'items') {
$queue = $items
->getEntity()
->getQueue();
if (($max_size = $queue
->getMaximumSize()) && !$queue
->getActAsQueue()) {
$this->fieldDefinition
->getFieldStorageDefinition()
->setCardinality($max_size);
}
}
return parent::form($items, $form, $form_state, $get_delta);
}
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
assert($items instanceof EntityReferenceFieldItemListInterface);
$entity_repository = \Drupal::service('entity.repository');
$referenced_entities = $items
->referencedEntities();
$field_name = $this->fieldDefinition
->getName();
if (isset($referenced_entities[$delta])) {
$entity = $entity_repository
->getTranslationFromContext($referenced_entities[$delta]);
$entity_label = $this
->getSetting('link_to_entity') && !$entity
->isNew() ? $entity
->toLink()
->toString() : $entity
->label();
$element += [
'#type' => 'container',
'#attributes' => [
'class' => [
'form--inline',
],
],
'target_id' => [
'#type' => 'item',
'#markup' => $entity
->access('view label') ? $entity_label : $this
->t('- Restricted access -'),
'#default_value' => !$referenced_entities[$delta]
->isNew() ? $referenced_entities[$delta]
->id() : NULL,
'#weight' => 0,
],
'_remove' => [
'#type' => 'submit',
'#name' => implode('_', array_merge($form['#parents'], [
$field_name,
$delta,
])) . '_remove',
'#delta' => $delta,
'#value' => $this
->t('Remove'),
'#attributes' => [
'class' => [
'remove-item-submit',
'align-right',
],
],
'#limit_validation_errors' => [
array_merge($form['#parents'], [
$field_name,
]),
],
'#submit' => [
[
get_class($this),
'removeSubmit',
],
],
'#ajax' => [
'callback' => [
get_class($this),
'removeAjax',
],
'wrapper' => $this
->getWrapperId(),
'effect' => 'fade',
],
],
];
if ($this
->getSetting('link_to_edit_form') && $referenced_entities[$delta]
->getEntityType()
->hasLinkTemplate('edit-form')) {
$element['_edit'] = $referenced_entities[$delta]
->toLink($this
->t('Edit'), 'edit-form', [
'query' => [
'destination' => \Drupal::request()
->getRequestUri(),
],
])
->toRenderable() + [
'#attributes' => [
'class' => [
'form-item',
'entityqueue-edit-item-link',
],
],
];
$element['#attached']['html_head'][] = [
[
'#tag' => 'style',
'#value' => '.js-form-wrapper .form-wrapper .form-item.entityqueue-edit-item-link { margin-left: 1em }',
],
'entityqueue-edit-item-link',
];
}
}
return $element;
}
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
if ($button = $form_state
->getTriggeringElement()) {
if (end($button['#parents']) === '_remove' && $violation
->getConstraint() instanceof ValidReferenceConstraint) {
return FALSE;
}
}
return parent::errorElement($element, $violation, $form, $form_state);
}
public static function removeSubmit(array &$form, FormStateInterface $form_state) {
$button = $form_state
->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
$field_name = $element['#field_name'];
$parents = $element['#field_parents'];
$form_state
->setValueForElement($element[$button['#delta']]['target_id'], NULL);
$items = $form_state
->getFormObject()
->getEntity()
->get($field_name);
$widget = $form_state
->getFormObject()
->getFormDisplay($form_state)
->getRenderer($field_name);
$widget
->extractFormValues($items, $form, $form_state);
foreach ($items as $item) {
unset($item->_remove);
}
$field_state = static::getWidgetState($parents, $field_name, $form_state);
$field_state['items_count']--;
static::setWidgetState($parents, $field_name, $form_state, $field_state);
$form_state
->setRebuild();
}
public static function removeAjax(array $form, FormStateInterface $form_state) {
$button = $form_state
->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
return $element;
}
protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
$field_name = $this->fieldDefinition
->getName();
$cardinality = $this->fieldDefinition
->getFieldStorageDefinition()
->getCardinality();
$parents = $form['#parents'];
$id_prefix = implode('-', array_merge($parents, [
$field_name,
]));
$wrapper_id = Html::getUniqueId($id_prefix . '-wrapper');
$this
->setWrapperId($wrapper_id);
$field_state = static::getWidgetState($parents, $field_name, $form_state);
$max = $field_state['items_count'];
$elements = [];
if ($max > 0) {
for ($delta = 0; $delta < $max; $delta++) {
$element = [
'#title' => $this
->t('@title (value @number)', [
'@title' => $this->fieldDefinition
->getLabel(),
'@number' => $delta + 1,
]),
'#title_display' => 'invisible',
'#description' => '',
];
$element = $this
->formSingleElement($items, $delta, $element, $form, $form_state);
if ($element) {
$element['_weight'] = [
'#type' => 'weight',
'#title' => $this
->t('Weight for row @number', [
'@number' => $delta + 1,
]),
'#title_display' => 'invisible',
'#delta' => $max,
'#default_value' => $items[$delta]->_weight ?: $delta,
'#weight' => 100,
];
$elements[$delta] = $element;
}
}
}
$elements += [
'#theme' => 'field_multiple_value_form',
'#field_name' => $field_name,
'#cardinality' => $cardinality,
'#cardinality_multiple' => TRUE,
'#required' => $this->fieldDefinition
->isRequired(),
'#title' => $this->fieldDefinition
->getLabel(),
'#description' => FieldFilteredMarkup::create(\Drupal::token()
->replace($this->fieldDefinition
->getDescription())),
'#max_delta' => count($items) - 1,
'#prefix' => '<div id="' . $this
->getWrapperId() . '">',
'#suffix' => '</div>',
];
if (($cardinality === FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || $field_state['items_count'] < $cardinality) && !$form_state
->isProgrammed()) {
$elements['add_more'] = [
'#type' => 'container',
'#tree' => TRUE,
'#attributes' => [
'class' => [
'form--inline',
],
],
'new_item' => parent::formElement($items, -1, [], $form, $form_state),
'submit' => [
'#type' => 'submit',
'#name' => strtr($id_prefix, '-', '_') . '_add_more',
'#value' => $this
->t('Add item'),
'#attributes' => [
'class' => [
'field-add-more-submit',
],
],
'#limit_validation_errors' => [
array_merge($parents, [
$field_name,
]),
],
'#submit' => [
[
get_class($this),
'addItemSubmit',
],
],
'#ajax' => [
'callback' => [
get_class($this),
'addItemAjax',
],
'wrapper' => $this
->getWrapperId(),
'effect' => 'fade',
],
],
];
}
return $elements;
}
public static function addItemSubmit(array $form, FormStateInterface $form_state) {
$button = $form_state
->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
$field_name = $element['#field_name'];
$parents = $element['#field_parents'];
$submitted_values = NestedArray::getValue($form_state
->getValues(), array_slice($button['#parents'], 0, -1));
if (isset($submitted_values['new_item']['target_id'])) {
$items = $form_state
->getFormObject()
->getEntity()
->get($field_name);
$items
->appendItem($submitted_values['new_item']);
$field_state = static::getWidgetState($parents, $field_name, $form_state);
$field_state['items_count']++;
static::setWidgetState($parents, $field_name, $form_state, $field_state);
}
$form_state
->setRebuild();
}
public static function addItemAjax(array $form, FormStateInterface $form_state) {
$button = $form_state
->getTriggeringElement();
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
$element['add_more']['new_item']['target_id']['#value'] = NULL;
$delta = $element['#max_delta'];
$element[$delta]['#prefix'] = '<div class="ajax-new-content">' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
$element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '</div>';
return $element;
}
public function setWrapperId($wrapperId) {
if (!$this->wrapperId) {
$this->wrapperId = $wrapperId;
}
}
public function getWrapperId() {
return $this->wrapperId;
}
}