123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- <?php
- namespace Drupal\Core\Field\Plugin\Field\FieldWidget;
- use Drupal\Core\Field\FieldItemListInterface;
- use Drupal\Core\Field\WidgetBase;
- use Drupal\Core\Form\FormStateInterface;
- use Drupal\user\EntityOwnerInterface;
- use Symfony\Component\Validator\ConstraintViolationInterface;
- /**
- * Plugin implementation of the 'entity_reference_autocomplete' widget.
- *
- * @FieldWidget(
- * id = "entity_reference_autocomplete",
- * label = @Translation("Autocomplete"),
- * description = @Translation("An autocomplete text field."),
- * field_types = {
- * "entity_reference"
- * }
- * )
- */
- class EntityReferenceAutocompleteWidget extends WidgetBase {
- /**
- * {@inheritdoc}
- */
- public static function defaultSettings() {
- return [
- 'match_operator' => 'CONTAINS',
- 'match_limit' => 10,
- 'size' => 60,
- 'placeholder' => '',
- ] + parent::defaultSettings();
- }
- /**
- * {@inheritdoc}
- */
- public function settingsForm(array $form, FormStateInterface $form_state) {
- $element['match_operator'] = [
- '#type' => 'radios',
- '#title' => t('Autocomplete matching'),
- '#default_value' => $this->getSetting('match_operator'),
- '#options' => $this->getMatchOperatorOptions(),
- '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of entities.'),
- ];
- $element['match_limit'] = [
- '#type' => 'number',
- '#title' => $this->t('Number of results'),
- '#default_value' => $this->getSetting('match_limit'),
- '#min' => 0,
- '#description' => $this->t('The number of suggestions that will be listed. Use <em>0</em> to remove the limit.'),
- ];
- $element['size'] = [
- '#type' => 'number',
- '#title' => t('Size of textfield'),
- '#default_value' => $this->getSetting('size'),
- '#min' => 1,
- '#required' => TRUE,
- ];
- $element['placeholder'] = [
- '#type' => 'textfield',
- '#title' => t('Placeholder'),
- '#default_value' => $this->getSetting('placeholder'),
- '#description' => t('Text that will be shown inside the field until a value is entered. This hint is usually a sample value or a brief description of the expected format.'),
- ];
- return $element;
- }
- /**
- * {@inheritdoc}
- */
- public function settingsSummary() {
- $summary = [];
- $operators = $this->getMatchOperatorOptions();
- $summary[] = t('Autocomplete matching: @match_operator', ['@match_operator' => $operators[$this->getSetting('match_operator')]]);
- $size = $this->getSetting('match_limit') ?: $this->t('unlimited');
- $summary[] = $this->t('Autocomplete suggestion list size: @size', ['@size' => $size]);
- $summary[] = t('Textfield size: @size', ['@size' => $this->getSetting('size')]);
- $placeholder = $this->getSetting('placeholder');
- if (!empty($placeholder)) {
- $summary[] = t('Placeholder: @placeholder', ['@placeholder' => $placeholder]);
- }
- else {
- $summary[] = t('No placeholder');
- }
- return $summary;
- }
- /**
- * {@inheritdoc}
- */
- public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
- $entity = $items->getEntity();
- $referenced_entities = $items->referencedEntities();
- // Append the match operation to the selection settings.
- $selection_settings = $this->getFieldSetting('handler_settings') + [
- 'match_operator' => $this->getSetting('match_operator'),
- 'match_limit' => $this->getSetting('match_limit'),
- ];
- $element += [
- '#type' => 'entity_autocomplete',
- '#target_type' => $this->getFieldSetting('target_type'),
- '#selection_handler' => $this->getFieldSetting('handler'),
- '#selection_settings' => $selection_settings,
- // Entity reference field items are handling validation themselves via
- // the 'ValidReference' constraint.
- '#validate_reference' => FALSE,
- '#maxlength' => 1024,
- '#default_value' => isset($referenced_entities[$delta]) ? $referenced_entities[$delta] : NULL,
- '#size' => $this->getSetting('size'),
- '#placeholder' => $this->getSetting('placeholder'),
- ];
- if ($bundle = $this->getAutocreateBundle()) {
- $element['#autocreate'] = [
- 'bundle' => $bundle,
- 'uid' => ($entity instanceof EntityOwnerInterface) ? $entity->getOwnerId() : \Drupal::currentUser()->id(),
- ];
- }
- return ['target_id' => $element];
- }
- /**
- * {@inheritdoc}
- */
- public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
- return $element['target_id'];
- }
- /**
- * {@inheritdoc}
- */
- public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
- foreach ($values as $key => $value) {
- // The entity_autocomplete form element returns an array when an entity
- // was "autocreated", so we need to move it up a level.
- if (is_array($value['target_id'])) {
- unset($values[$key]['target_id']);
- $values[$key] += $value['target_id'];
- }
- }
- return $values;
- }
- /**
- * Returns the name of the bundle which will be used for autocreated entities.
- *
- * @return string
- * The bundle name. If autocreate is not active, NULL will be returned.
- */
- protected function getAutocreateBundle() {
- $bundle = NULL;
- if ($this->getSelectionHandlerSetting('auto_create')) {
- $target_bundles = $this->getSelectionHandlerSetting('target_bundles');
- // If there's no target bundle at all, use the target_type. It's the
- // default for bundleless entity types.
- if (empty($target_bundles)) {
- $bundle = $this->getFieldSetting('target_type');
- }
- // If there's only one target bundle, use it.
- elseif (count($target_bundles) == 1) {
- $bundle = reset($target_bundles);
- }
- // If there's more than one target bundle, use the autocreate bundle
- // stored in selection handler settings.
- elseif (!$bundle = $this->getSelectionHandlerSetting('auto_create_bundle')) {
- // If no bundle has been set as auto create target means that there is
- // an inconsistency in entity reference field settings.
- trigger_error(sprintf(
- "The 'Create referenced entities if they don't already exist' option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.",
- $this->fieldDefinition->getLabel(),
- $this->fieldDefinition->getName()
- ), E_USER_WARNING);
- }
- }
- return $bundle;
- }
- /**
- * Returns the value of a setting for the entity reference selection handler.
- *
- * @param string $setting_name
- * The setting name.
- *
- * @return mixed
- * The setting value.
- */
- protected function getSelectionHandlerSetting($setting_name) {
- $settings = $this->getFieldSetting('handler_settings');
- return isset($settings[$setting_name]) ? $settings[$setting_name] : NULL;
- }
- /**
- * Returns the options for the match operator.
- *
- * @return array
- * List of options.
- */
- protected function getMatchOperatorOptions() {
- return [
- 'STARTS_WITH' => t('Starts with'),
- 'CONTAINS' => t('Contains'),
- ];
- }
- }
|