FALSE,
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
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'),
];
return $elements;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = parent::settingsSummary();
$settings = $this->getSettings();
if (!empty($settings['link_to_entity'])) {
$summary[] = $this->t('Link to the referenced entity');
}
return $summary;
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$field_name = $this->fieldDefinition->getName();
$parents = $form['#parents'];
$referenced_entities = $items->referencedEntities();
if (isset($referenced_entities[$delta])) {
if ($this->getSetting('link_to_entity') && !$referenced_entities[$delta]->isNew()) {
$entity_label = $referenced_entities[$delta]->toLink()->toString();
}
else {
$entity_label = $referenced_entities[$delta]->label();
}
$id_prefix = implode('-', array_merge($parents, [$field_name, $delta]));
$element += [
'#type' => 'container',
'#attributes' => ['class' => ['form--inline']],
'target_id' => [
'#type' => 'item',
'#markup' => $entity_label,
'#default_value' => !$referenced_entities[$delta]->isNew() ? $referenced_entities[$delta]->id() : NULL,
],
'entity' => [
'#type' => 'value',
'#default_value' => $referenced_entities[$delta],
],
'remove' => [
'#type' => 'submit',
'#name' => strtr($id_prefix, '-', '_') . '_remove',
'#value' => $this->t('Remove'),
'#attributes' => ['class' => ['remove-item-submit', 'align-right']],
'#submit' => [[get_class($this), 'removeSubmit']],
'#ajax' => [
'callback' => [get_class($this), 'getWidgetElementAjax'],
'wrapper' => $this->getWrapperId(),
'effect' => 'fade',
],
],
];
}
return $element;
}
/**
* {@inheritdoc}
*/
protected function formMultipleElements(FieldItemListInterface $items, array &$form, FormStateInterface $form_state) {
$field_name = $this->fieldDefinition->getName();
$cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
$parents = $form['#parents'];
// Assign a unique identifier to each widget.
$id_prefix = implode('-', array_merge($parents, [$field_name]));
$wrapper_id = Html::getUniqueId($id_prefix . '-add-more-wrapper');
$this->setWrapperId($wrapper_id);
// Load the items for form rebuilds from the field state as they might not
// be in $form_state->getValues() because of validation limitations. Also,
// they are only passed in as $items when editing existing entities.
$field_state = static::getWidgetState($parents, $field_name, $form_state);
if (isset($field_state['items'])) {
$items->setValue($field_state['items']);
}
// Lower the 'items_count' field state property in order to prevent the
// parent implementation to append an extra empty item.
if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
$field_state['items_count'] = (count($items) > 1) ? count($items) - 1 : 0;
static::setWidgetState($parents, $field_name, $form_state, $field_state);
}
$elements = parent::formMultipleElements($items, $form, $form_state);
if ($elements) {
if (isset($elements['add_more'])) {
// Update the HTML wrapper ID with the one generated by us.
$elements['#prefix'] = '
';
$add_more_button = $elements['add_more'];
$add_more_button['#value'] = $this->t('Add item');
$add_more_button['#ajax']['callback'] = [get_class($this), 'getWidgetElementAjax'];
$add_more_button['#ajax']['wrapper'] = $this->getWrapperId();
$elements['add_more'] = [
'#type' => 'container',
'#tree' => TRUE,
'#attributes' => ['class' => ['form--inline']],
'new_item' => parent::formElement($items, -1, [], $form, $form_state),
'submit' => $add_more_button,
];
}
}
return $elements;
}
/**
* {@inheritdoc}
*/
public static function getWidgetElementAjax(array $form, FormStateInterface $form_state) {
$button = $form_state->getTriggeringElement();
// Go two levels up in the form, to the widgets container.
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -2));
// Ensure the widget allows adding additional items.
if ($element['#cardinality'] != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
return;
}
// Add a DIV around the delta receiving the Ajax effect.
$delta = $element['#max_delta'];
$element[$delta]['#prefix'] = '
' . (isset($element[$delta]['#prefix']) ? $element[$delta]['#prefix'] : '');
$element[$delta]['#suffix'] = (isset($element[$delta]['#suffix']) ? $element[$delta]['#suffix'] : '') . '
';
return $element;
}
/**
* {@inheritdoc}
*/
public static function addMoreSubmit(array $form, FormStateInterface $form_state) {
// During the form rebuild, formElement() will create field item widget
// elements using re-indexed deltas, so clear out FormState::$input to
// avoid a mismatch between old and new deltas. The rebuilt elements will
// have #default_value set appropriately for the current state of the field,
// so nothing is lost in doing this.
$button = $form_state->getTriggeringElement();
$parents = array_slice($button['#parents'], 0, -2);
NestedArray::setValue($form_state->getUserInput(), $parents, NULL);
// Go two levels up in the form, to the widgets container.
$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, -2));
// Check submitted values for empty items.
$new_values = [];
foreach ($submitted_values as $delta => $submitted_value) {
if ($delta !== 'add_more' && (isset($submitted_value['target_id']) || isset($submitted_value['entity']))) {
$new_values[] = $submitted_value;
}
if ($delta === 'add_more' && (isset($submitted_value['new_item']['target_id']) || isset($submitted_value['new_item']['entity']))) {
$new_values[] = $submitted_value['new_item'];
}
}
// Re-index deltas after removing empty items.
$submitted_values = array_values($new_values);
// Update form_state values.
NestedArray::setValue($form_state->getValues(), array_slice($button['#parents'], 0, -2), $submitted_values);
// Update items.
$field_state = static::getWidgetState($parents, $field_name, $form_state);
$field_state['items'] = $submitted_values;
static::setWidgetState($parents, $field_name, $form_state, $field_state);
$form_state->setRebuild();
}
/**
* Submission handler for the "Remove" button.
*/
public static function removeSubmit(array $form, FormStateInterface $form_state) {
$button = $form_state->getTriggeringElement();
// Go one level up in the form, to the single field item element container.
$element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1));
$form_state->setValueForElement($element, ['target_id' => NULL, 'entity' => NULL]);
// Call the generic submit handler which takes care of removing the item.
static::addMoreSubmit($form, $form_state);
}
/**
* Sets the unique HTML ID of the widget's wrapping element.
*
* @param string $wrapperId
* The unique HTML ID.
*/
public function setWrapperId($wrapperId) {
if (!$this->wrapperId) {
$this->wrapperId = $wrapperId;
}
}
/**
* Gets the unique HTML ID of the widget's wrapping element.
*
* @return string
* The unique HTML ID.
*/
public function getWrapperId() {
return $this->wrapperId;
}
}