pluginreference-2.0.0/src/Plugin/Field/FieldWidget/PluginReferenceOptionsButtonsWidget.php
src/Plugin/Field/FieldWidget/PluginReferenceOptionsButtonsWidget.php
<?php
namespace Drupal\pluginreference\Plugin\Field\FieldWidget;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\Attribute\FieldWidget;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldFilteredMarkup;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\TypedData\OptionsProviderInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'plugin_reference_options_buttons' widget.
*/
#[FieldWidget(
id: 'plugin_reference_options_buttons',
label: new TranslatableMarkup('Check boxes/radio buttons'),
field_types: [
'plugin_reference',
],
multiple_values: TRUE,
)]
class PluginReferenceOptionsButtonsWidget extends WidgetBase {
use PluginReferenceConfigurationFormTrait;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* Boolean indicating if the field is required.
*
* @var bool
*/
protected $required;
/**
* Boolean indicating if the field contains multiple values.
*
* @var bool
*/
protected $multiple;
/**
* {@inheritdoc}
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, array $third_party_settings, AccountProxyInterface $current_user) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $third_party_settings);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['third_party_settings'],
$container->get('current_user')
);
}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return self::configurationDefaultSettings() + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
return parent::settingsForm($form, $form_state) + $this->configurationSettingsForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
return parent::settingsSummary() + $this->configurationSettingsSummary();
}
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
// Prepare some properties for the child methods to build the actual form
// element.
$this->required = $element['#required'];
$this->multiple = $this->fieldDefinition->getFieldStorageDefinition()->isMultiple();
$options = $this->getOptions($items->getEntity());
$selected = $this->getSelectedOptions($items);
if (!$this->multiple) {
$selected = !empty($selected) ? reset($selected) : NULL;
}
// If required and there is one single option, preselect it.
if ($this->required && empty($selected) && count($options) == 1) {
reset($options);
$selected = [key($options)];
}
$element['plugin_id'] = [
'#type' => $this->multiple ? 'checkboxes' : 'radios',
'#default_value' => $selected,
'#options' => $this->getOptions($items->getEntity()),
] + $element;
return $this->multipleConfigurationFormElements($items, $delta, $element, $form, $form_state);
}
/**
* Build the options used by this widget.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity for which to return options.
*
* @return array
* An array of options.
*/
public function getOptions(FieldableEntityInterface $entity): array {
$options_provider = $this->fieldDefinition
->getFieldStorageDefinition()
->getOptionsProvider('plugin_id', $entity);
$options = [];
if ($options_provider instanceof OptionsProviderInterface) {
$options = $options_provider->getSettableOptions($this->currentUser);
}
// Add an empty option if the widget needs one.
if (!$this->required && !$this->multiple) {
$options = ['_none' => $this->t('N/A')] + $options;
}
array_walk_recursive($options, [$this, 'sanitizeLabel']);
return $options;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
$values = parent::massageFormValues($values, $form, $form_state);
$new_values = [];
if (!is_array($values['plugin_id'])) {
$values['plugin_id'] = [$values['plugin_id']];
}
if (isset($values['plugin_id'])) {
foreach ($values['plugin_id'] as $value) {
if (!empty($value)) {
$new_values[] = [
'plugin_id' => $value,
'configuration' => $values['configuration'][$value] ?? [],
];
}
}
}
return $new_values;
}
/**
* Determines selected options from the incoming field values.
*
* @param \Drupal\Core\Field\FieldItemListInterface $items
* The field values.
*
* @return array
* The array of corresponding selected options.
*/
protected function getSelectedOptions(FieldItemListInterface $items): array {
// We need to check against a flat list of options.
$flat_options = $this->getOptions($items->getEntity());
$selected_options = [];
foreach ($items as $item) {
$value = $item->plugin_id;
// Keep the value if it actually is in the list of options (needs to be
// checked against the flat list).
if (isset($flat_options[$value])) {
$selected_options[] = $value;
}
}
return $selected_options;
}
/**
* Sanitizes a string label to display as an option.
*
* @param string $label
* The label to sanitize.
*/
protected function sanitizeLabel(&$label): void {
// Allow a limited set of HTML tags.
$label = FieldFilteredMarkup::create($label);
}
}
