trait WebformEntityReferenceTrait in Webform 8.5
Same name and namespace in other branches
- 6.x src/Plugin/WebformElement/WebformEntityReferenceTrait.php \Drupal\webform\Plugin\WebformElement\WebformEntityReferenceTrait
Provides an 'entity_reference' trait.
Hierarchy
- trait \Drupal\webform\Plugin\WebformElement\WebformEntityReferenceTrait uses WebformAjaxElementTrait
1 file declares its use of WebformEntityReferenceTrait
- WebformOptionsCustomEntity.php in modules/
webform_options_custom/ src/ Plugin/ WebformElement/ WebformOptionsCustomEntity.php
File
- src/
Plugin/ WebformElement/ WebformEntityReferenceTrait.php, line 19
Namespace
Drupal\webform\Plugin\WebformElementView source
trait WebformEntityReferenceTrait {
use WebformAjaxElementTrait;
/**
* {@inheritdoc}
*/
public function getRelatedTypes(array $element) {
$types = [];
$plugin_id = $this
->getPluginId();
$elements = $this->elementManager
->getInstances();
foreach ($elements as $element_name => $element_instance) {
// Skip self.
if ($plugin_id === $element_instance
->getPluginId()) {
continue;
}
if ($element_instance instanceof WebformElementEntityReferenceInterface) {
$types[$element_name] = $element_instance
->getPluginLabel();
}
}
asort($types);
return $types;
}
/**
* {@inheritdoc}
*/
protected function formatHtmlItem(array $element, WebformSubmissionInterface $webform_submission, array $options = []) {
$entity = $this
->getTargetEntity($element, $webform_submission, $options);
if (empty($entity)) {
return '';
}
$format = $this
->getItemFormat($element);
switch ($format) {
case 'raw':
case 'value':
case 'id':
case 'label':
case 'text':
case 'breadcrumb':
return $this
->formatTextItem($element, $webform_submission, $options);
case 'link':
if ($entity
->hasLinkTemplate('canonical')) {
return [
'#type' => 'link',
'#title' => $entity
->label(),
'#url' => $entity
->toUrl()
->setAbsolute(TRUE),
];
}
else {
switch ($entity
->getEntityTypeId()) {
case 'file':
/** @var \Drupal\file\FileInterface $entity */
if ($entity
->access('download')) {
return [
'#type' => 'link',
'#title' => $entity
->label(),
'#url' => UrlGenerator::fromUri(file_create_url($entity
->getFileUri())),
];
}
else {
return $this
->formatTextItem($element, $webform_submission, $options);
}
default:
return $this
->formatTextItem($element, $webform_submission, $options);
}
}
default:
return \Drupal::entityTypeManager()
->getViewBuilder($entity
->getEntityTypeId())
->view($entity, $format);
}
}
/**
* {@inheritdoc}
*/
protected function formatTextItem(array $element, WebformSubmissionInterface $webform_submission, array $options = []) {
$entity = $this
->getTargetEntity($element, $webform_submission, $options);
if (!$entity) {
return '';
}
$format = $this
->getItemFormat($element);
switch ($format) {
case 'id':
return $entity
->id();
case 'breadcrumb':
if ($entity
->getEntityTypeId() === 'taxonomy_term') {
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
$taxonomy_storage = \Drupal::entityTypeManager()
->getStorage('taxonomy_term');
$parents = $taxonomy_storage
->loadAllParents($entity
->id());
$breadcrumb = [];
foreach ($parents as $parent) {
$breadcrumb[] = $parent
->label();
}
$element += [
'#delimiter' => ' › ',
];
return implode($element['#delimiter'], array_reverse($breadcrumb));
}
return $entity
->label();
case 'label':
return $entity
->label();
case 'raw':
$entity_id = $entity
->id();
$entity_type = $entity
->getEntityTypeId();
return "{$entity_type}:{$entity_id}";
case 'text':
default:
return sprintf('%s (%s)', $entity
->label(), $entity
->id());
}
}
/**
* {@inheritdoc}
*/
public function getTestValues(array $element, WebformInterface $webform, array $options = []) {
$this
->setOptions($element, [
'limit' => 10,
'random' => TRUE,
]);
// Exclude 'anonymous' user.
$target_type = $this
->getTargetType($element);
if ($target_type === 'user') {
unset($element['#options'][0]);
}
return array_keys($element['#options']);
}
/**
* {@inheritdoc}
*/
public function isMultiline(array $element) {
if ($this
->hasMultipleValues($element)) {
return TRUE;
}
else {
return parent::isMultiline($element);
}
}
/**
* {@inheritdoc}
*/
public function getItemDefaultFormat() {
return 'link';
}
/**
* {@inheritdoc}
*/
public function getItemFormats() {
$formats = parent::getItemFormats() + [
'link' => $this
->t('Link'),
'id' => $this
->t('Entity ID'),
'label' => $this
->t('Label'),
'text' => $this
->t('Label (ID)'),
'teaser' => $this
->t('Teaser'),
'default' => $this
->t('Default'),
];
if ($this
->hasProperty('breadcrumb')) {
$formats['breadcrumb'] = $this
->t('Breadcrumb');
}
return $formats;
}
/**
* {@inheritdoc}
*/
public function preview() {
$element = parent::preview();
$element += [
'#target_type' => 'user',
'#selection_handler' => 'default:user',
'#selection_settings' => [
'include_anonymous' => TRUE,
],
];
if ($this instanceof OptionsBase) {
$element['#options'] = [
'1' => 'Administrator',
'0' => 'Anonymous',
];
}
return $element;
}
/**
* {@inheritdoc}
*/
public function buildExportOptionsForm(array &$form, FormStateInterface $form_state, array $export_options) {
if (isset($form['entity_reference'])) {
return;
}
$form['entity_reference'] = [
'#type' => 'details',
'#title' => $this
->t('Entity reference options'),
'#open' => TRUE,
];
$form['entity_reference']['entity_reference_items'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Entity reference format'),
'#options' => [
'id' => $this
->t("ID, an entity's unique identified"),
'title' => $this
->t("Title, an entity's title/label"),
'url' => $this
->t("URL, an entity's URL"),
],
'#required' => TRUE,
'#default_value' => $export_options['entity_reference_items'],
'#element_validate' => [
[
get_class($this),
'validateEntityReferenceFormat',
],
],
];
}
/**
* Form API callback. Remove unchecked options from value array.
*/
public static function validateEntityReferenceFormat(array &$element, FormStateInterface $form_state, array &$completed_form) {
$values = $element['#value'];
// Filter unchecked/unselected options whose value is 0.
$values = array_filter($values, function ($value) {
return $value !== 0;
});
$values = array_values($values);
$form_state
->setValueForElement($element, $values);
}
/**
* {@inheritdoc}
*/
public function buildExportHeader(array $element, array $options) {
if (!$this
->hasMultipleValues($element)) {
$default_options = $this
->getExportDefaultOptions();
$header = isset($options['entity_reference_items']) ? $options['entity_reference_items'] : $default_options['entity_reference_items'];
if ($options['header_format'] === 'label') {
foreach ($header as $index => $column) {
switch ($column) {
case 'id':
$header[$index] = $this
->t('ID');
break;
case 'title':
$header[$index] = $this
->t('Title');
break;
case 'url':
$header[$index] = $this
->t('URL');
break;
}
}
}
return $this
->prefixExportHeader($header, $element, $options);
}
else {
return parent::buildExportHeader($element, $options);
}
}
/**
* {@inheritdoc}
*/
public function buildExportRecord(array $element, WebformSubmissionInterface $webform_submission, array $export_options) {
$value = $this
->getValue($element, $webform_submission);
$default_options = $this
->getExportDefaultOptions();
$entity_reference_items = isset($export_options['entity_reference_items']) ? $export_options['entity_reference_items'] : $default_options['entity_reference_items'];
if (!$this
->hasMultipleValues($element)) {
$entity_type = $this
->getTargetType($element);
$entity_storage = $this->entityTypeManager
->getStorage($entity_type);
$entity_id = $value;
$record = [];
if ($entity_id && ($entity = $entity_storage
->load($entity_id))) {
foreach ($entity_reference_items as $column) {
switch ($column) {
case 'id':
$record[] = $entity
->id();
break;
case 'title':
$record[] = $entity
->label();
break;
case 'url':
if ($entity
->hasLinkTemplate('canonical')) {
$record[] = $entity
->toUrl('canonical', [
'absolute' => TRUE,
])
->toString();
}
else {
$record[] = '';
}
break;
}
}
}
else {
foreach ($entity_reference_items as $column) {
switch ($column) {
case 'id':
$record[] = $entity_id;
break;
case 'title':
$record[] = '';
break;
case 'url':
$record[] = '';
break;
}
}
}
return $record;
}
else {
if ($entity_reference_items === [
'id',
]) {
$element['#format'] = 'raw';
}
return parent::buildExportRecord($element, $webform_submission, $export_options);
}
}
/**
* Get element options.
*
* @param array $element
* An element.
* @param array $settings
* An array of settings used to limit and randomize options.
*/
protected function setOptions(array &$element, array $settings = []) {
// Add the webform submission to entity reference selection settings.
if (!isset($settings['webform_submission']) && !empty($element['#webform_submission'])) {
$settings['webform_submission'] = WebformSubmission::load($element['#webform_submission']);
}
// Replace tokens element just in case entity selection settings use tokens.
if (isset($settings['webform_submission'])) {
$this
->replaceTokens($element, $settings['webform_submission']);
}
WebformEntityTrait::setOptions($element, $settings);
// Set options all after entity options are defined.
if (!empty($element['#options_all'])) {
$element['#options'][$element['#options_all_value']] = $element['#options_all_text'];
}
}
/**
* {@inheritdoc}
*/
public function getTargetType(array $element) {
return $element['#target_type'];
}
/**
* {@inheritdoc}
*/
public function getTargetEntity(array $element, WebformSubmissionInterface $webform_submission, array $options = []) {
$value = $this
->getValue($element, $webform_submission, $options);
if (empty($value)) {
return NULL;
}
$entities = $this
->getTargetEntities($element, $webform_submission, $options);
return reset($entities);
}
/**
* {@inheritdoc}
*/
public function getTargetEntities(array $element, WebformSubmissionInterface $webform_submission, array $options = []) {
$value = $this
->getValue($element, $webform_submission, $options);
if (empty($value)) {
return [];
}
if (!is_array($value)) {
$value = [
$value,
];
}
/** @var \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository */
$entity_repository = \Drupal::service('entity.repository');
$target_type = $this
->getTargetType($element);
$entities = $this->entityTypeManager
->getStorage($target_type)
->loadMultiple($value);
foreach ($entities as $entity_id => $entity) {
// Set the entity in the correct language for display.
$entities[$entity_id] = $entity_repository
->getTranslationFromContext($entity);
}
return $entities;
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
/**************************************************************************/
// IMPORTANT: Most of the below code and #ajax tweaks compensate for the
// fact that the EntityReferenceSelection plugin specifically targets
// entity references managed via the Field API.
// @see \Drupal\webform\Plugin\WebformElementBase::setConfigurationFormDefaultValueRecursive
// @see \Drupal\webform\Plugin\WebformElementBase::buildConfigurationForm
/**************************************************************************/
// Get element properties.
$element_properties = $form_state
->get('element_properties');
// Alter element properties.
if ($form_state
->isRebuilding()) {
// Get entity reference value from user input because
// $form_state->getValue() does not always contain every input's value.
$user_input = $form_state
->getUserInput();
$target_type = !empty($user_input['properties']['target_type']) ? $user_input['properties']['target_type'] : 'node';
$selection_handler = !empty($user_input['properties']['selection_handler']) ? $user_input['properties']['selection_handler'] : 'default:' . $target_type;
$selection_settings = !empty($user_input['properties']['selection_settings']) ? $user_input['properties']['selection_settings'] : [];
// If the default selection handler has changed when need to update its
// value.
if (strpos($selection_handler, 'default:') === 0 && $selection_handler !== "default:{$target_type}") {
$selection_handler = "default:{$target_type}";
$selection_settings = [];
NestedArray::setValue($form_state
->getUserInput(), [
'properties',
'selection_handler',
], $selection_handler);
NestedArray::setValue($form_state
->getUserInput(), [
'properties',
'selection_settings',
], $selection_settings);
}
}
else {
// Set default #target_type and #selection_handler.
if (empty($element_properties['target_type'])) {
$element_properties['target_type'] = 'node';
}
if (empty($element_properties['selection_handler'])) {
$element_properties['selection_handler'] = 'default:' . $element_properties['target_type'];
}
$target_type = $element_properties['target_type'];
$selection_handler = $element_properties['selection_handler'];
$selection_settings = $element_properties['selection_settings'];
}
// Set 'User' entity reference selection filter type role's #default_value
// to an array and not NULL, which throws
// "Warning: Invalid argument supplied for foreach()
// in Drupal\Core\Render\Element\Checkboxes::valueCallback()"
// @see \Drupal\user\Plugin\EntityReferenceSelection\UserSelection::buildConfigurationForm
if ($target_type === 'user' && isset($selection_settings['filter']['type']) && $selection_settings['filter']['type'] === 'role' && empty($selection_settings['filter']['role'])) {
$selection_settings['filter']['role'] = [];
}
// Reset element properties.
$element_properties['target_type'] = $target_type;
$element_properties['selection_handler'] = $selection_handler;
$element_properties['selection_settings'] = $selection_settings;
$form_state
->set('element_properties', $element_properties);
/**************************************************************************/
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $entity_reference_selection_manager */
$entity_reference_selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
// @see \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem
$selection_plugins = $entity_reference_selection_manager
->getSelectionGroups($target_type);
$handlers_options = [];
foreach (array_keys($selection_plugins) as $selection_group_id) {
if (array_key_exists($selection_group_id, $selection_plugins[$selection_group_id])) {
$handlers_options[$selection_group_id] = Html::escape($selection_plugins[$selection_group_id][$selection_group_id]['label']);
}
elseif (array_key_exists($selection_group_id . ':' . $target_type, $selection_plugins[$selection_group_id])) {
$selection_group_plugin = $selection_group_id . ':' . $target_type;
$handlers_options[$selection_group_plugin] = Html::escape($selection_plugins[$selection_group_id][$selection_group_plugin]['base_plugin_label']);
}
}
// Entity Reference fields are no longer supported to reference Paragraphs.
// @see paragraphs_form_field_storage_config_edit_form_alter()
$target_type_options = \Drupal::service('entity_type.repository')
->getEntityTypeLabels(TRUE);
unset($target_type_options[(string) $this
->t('Content')]['paragraph']);
$form['entity_reference'] = [
'#type' => 'fieldset',
'#title' => $this
->t('Entity reference settings'),
'#weight' => -40,
];
// Target type.
$form['entity_reference']['target_type'] = [
'#type' => 'select',
'#title' => $this
->t('Type of item to reference'),
'#options' => $target_type_options,
'#required' => TRUE,
'#empty_option' => $this
->t('- Select a target type -'),
'#default_value' => $target_type,
];
// Selection handler.
$form['entity_reference']['selection_handler'] = [
'#type' => 'select',
'#title' => $this
->t('Reference method'),
'#options' => $handlers_options,
'#required' => TRUE,
'#default_value' => $selection_handler,
];
// Selection settings.
// Note: The below options are used to populate the #default_value for
// selection settings.
$entity_reference_selection_handler = $entity_reference_selection_manager
->getInstance([
'target_type' => $target_type,
'handler' => $selection_handler,
] + $selection_settings);
$form['entity_reference']['selection_settings'] = $entity_reference_selection_handler
->buildConfigurationForm([], $form_state);
$form['entity_reference']['selection_settings']['#tree'] = TRUE;
// Remove the no-ajax submit button because we are not using the
// EntityReferenceSelection with in Field API.
unset($form['entity_reference']['selection_settings']['target_bundles_update']);
// Remove auto create, except for entity_autocomplete.
if ($this
->getPluginId() !== 'entity_autocomplete' || $target_type !== 'taxonomy_term') {
unset($form['entity_reference']['selection_settings']['auto_create'], $form['entity_reference']['selection_settings']['auto_create_bundle']);
}
// Add hide/show #format_items based on #tags.
if ($this
->supportsMultipleValues() && $this
->hasProperty('tags')) {
$form['display']['format_items']['#states'] = [
'visible' => [
[
':input[name="properties[tags]"]' => [
'checked' => TRUE,
],
],
],
];
}
// Apply ajax handling.
$ajax_id = 'webform-entity-reference';
$this
->buildAjaxElementWrapper($ajax_id, $form['entity_reference']);
$this
->buildAjaxElementUpdate($ajax_id, $form['entity_reference']);
$this
->buildAjaxElementTrigger($ajax_id, $form['entity_reference']['target_type']);
$this
->buildAjaxElementTrigger($ajax_id, $form['entity_reference']['selection_handler']);
$this
->buildAjaxElementTriggerRecursive($ajax_id, $form['entity_reference']['selection_settings']);
// Tags (only applies to 'entity_autocomplete' element).
$form['element']['tags'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Tags'),
'#description' => $this
->t('Check this option if the user should be allowed to enter multiple entity references using tags.'),
'#return_value' => TRUE,
];
if ($this
->hasProperty('tags') && $this
->hasProperty('multiple')) {
$form['element']['multiple']['#states'] = [
'disabled' => [
':input[name="properties[tags]"]' => [
'checked' => TRUE,
],
],
];
$form['element']['multiple__header_container']['#states']['visible'][] = [
':input[name="properties[tags]"]' => [
'checked' => FALSE,
],
];
$form['element']['tags']['#states'] = [
'visible' => [
':input[name="properties[multiple][container][cardinality]"]' => [
'!value' => -1,
],
':input[name="properties[multiple][container][cardinality_number]"]' => [
'value' => 1,
],
],
];
}
// Disable tags in multiple is disabled.
if (!empty($form['element']['multiple']['#disabled'])) {
$form['element']['tags']['#disabled'] = $form['element']['multiple']['#disabled'];
$form['element']['tags']['#description'] = $form['element']['multiple']['#description'];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$values = $form_state
->getValues();
if (isset($values['selection_settings']['target_bundles']) && empty($values['selection_settings']['target_bundles'])) {
unset($values['selection_settings']['target_bundles']);
}
if (isset($values['selection_settings']['sort']['field']) && $values['selection_settings']['sort']['field'] === '_none') {
unset($values['selection_settings']['sort']);
}
// Convert auto_create and include_anonymous into boolean.
if (isset($values['selection_settings']['auto_create'])) {
$values['selection_settings']['auto_create'] = (bool) $values['selection_settings']['auto_create'];
}
if (isset($values['selection_settings']['include_anonymous'])) {
$values['selection_settings']['include_anonymous'] = (bool) $values['selection_settings']['include_anonymous'];
}
$form_state
->setValues($values);
}
/****************************************************************************/
// Form/Ajax helpers and callbacks.
/****************************************************************************/
/**
* Build an ajax elements trigger.
*
* @param string $id
* The id used to create the ajax wrapper and trigger.
* @param array &$element
* The elements to trigger the Ajax update.
*/
protected function buildAjaxElementTriggerRecursive($id, array &$element) {
$element['#access'] = TRUE;
foreach (Element::children($element) as $key) {
// Replace #ajax = TRUE with custom ajax element trigger attribute.
if (isset($element[$key]['#ajax']) && $element[$key]['#ajax'] === TRUE) {
$this
->buildAjaxElementTrigger($id, $element[$key]);
}
unset($element[$key]['#ajax'], $element[$key]['#limit_validation_errors']);
$this
->buildAjaxElementTriggerRecursive($id, $element[$key]);
}
}
/****************************************************************************/
// Display submission value methods.
/****************************************************************************/
/**
* {@inheritdoc}
*/
protected function formatHtmlItems(array &$element, WebformSubmissionInterface $webform_submission, array $options = []) {
$format = $this
->getItemsFormat($element);
if (strpos($format, 'checklist:') === 0) {
$this
->setOptions($element);
}
return parent::formatHtmlItems($element, $webform_submission, $options);
}
/**
* {@inheritdoc}
*/
protected function formatTextItems(array &$element, WebformSubmissionInterface $webform_submission, array $options = []) {
$format = $this
->getItemsFormat($element);
if (strpos($format, 'checklist:') === 0) {
$this
->setOptions($element);
}
return parent::formatTextItems($element, $webform_submission, $options);
}
}