Issue #2718697 by damiankloip, dawehner: EntityAutocomplete element cannot handle GET input values
parent
853202a000
commit
677116e149
|
@ -57,19 +57,33 @@ class EntityAutocomplete extends Textfield {
|
|||
if (is_array($element['#default_value']) && $element['#tags'] !== TRUE) {
|
||||
throw new \InvalidArgumentException('The #default_value property is an array but the form element does not allow multiple values.');
|
||||
}
|
||||
elseif (!is_array($element['#default_value'])) {
|
||||
elseif (!empty($element['#default_value']) && !is_array($element['#default_value'])) {
|
||||
// Convert the default value into an array for easier processing in
|
||||
// static::getEntityLabels().
|
||||
$element['#default_value'] = array($element['#default_value']);
|
||||
}
|
||||
|
||||
if ($element['#default_value'] && !(reset($element['#default_value']) instanceof EntityInterface)) {
|
||||
throw new \InvalidArgumentException('The #default_value property has to be an entity object or an array of entity objects.');
|
||||
}
|
||||
if ($element['#default_value']) {
|
||||
if (!(reset($element['#default_value']) instanceof EntityInterface)) {
|
||||
throw new \InvalidArgumentException('The #default_value property has to be an entity object or an array of entity objects.');
|
||||
}
|
||||
|
||||
// Extract the labels from the passed-in entity objects, taking access
|
||||
// checks into account.
|
||||
return static::getEntityLabels($element['#default_value']);
|
||||
// Extract the labels from the passed-in entity objects, taking access
|
||||
// checks into account.
|
||||
return static::getEntityLabels($element['#default_value']);
|
||||
}
|
||||
}
|
||||
|
||||
// Potentially the #value is set directly, so it contains the 'target_id'
|
||||
// array structure instead of a string.
|
||||
if ($input !== FALSE && is_array($input)) {
|
||||
$entity_ids = array_map(function(array $item) {
|
||||
return $item['target_id'];
|
||||
}, $input);
|
||||
|
||||
$entities = \Drupal::entityTypeManager()->getStorage($element['#target_type'])->loadMultiple($entity_ids);
|
||||
|
||||
return static::getEntityLabels($entities);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,6 +150,7 @@ class EntityAutocomplete extends Textfield {
|
|||
*/
|
||||
public static function validateEntityAutocomplete(array &$element, FormStateInterface $form_state, array &$complete_form) {
|
||||
$value = NULL;
|
||||
|
||||
if (!empty($element['#value'])) {
|
||||
$options = array(
|
||||
'target_type' => $element['#target_type'],
|
||||
|
@ -146,27 +161,35 @@ class EntityAutocomplete extends Textfield {
|
|||
$handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options);
|
||||
$autocreate = (bool) $element['#autocreate'] && $handler instanceof SelectionWithAutocreateInterface;
|
||||
|
||||
$input_values = $element['#tags'] ? Tags::explode($element['#value']) : array($element['#value']);
|
||||
foreach ($input_values as $input) {
|
||||
$match = static::extractEntityIdFromAutocompleteInput($input);
|
||||
if ($match === NULL) {
|
||||
// Try to get a match from the input string when the user didn't use
|
||||
// the autocomplete but filled in a value manually.
|
||||
$match = static::matchEntityByTitle($handler, $input, $element, $form_state, !$autocreate);
|
||||
}
|
||||
// GET forms might pass the validated data around on the next request, in
|
||||
// which case it will already be in the expected format.
|
||||
if (is_array($element['#value'])) {
|
||||
$value = $element['#value'];
|
||||
}
|
||||
else {
|
||||
$input_values = $element['#tags'] ? Tags::explode($element['#value']) : array($element['#value']);
|
||||
|
||||
if ($match !== NULL) {
|
||||
$value[] = array(
|
||||
'target_id' => $match,
|
||||
);
|
||||
}
|
||||
elseif ($autocreate) {
|
||||
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface $handler */
|
||||
// Auto-create item. See an example of how this is handled in
|
||||
// \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave().
|
||||
$value[] = array(
|
||||
'entity' => $handler->createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $input, $element['#autocreate']['uid']),
|
||||
);
|
||||
foreach ($input_values as $input) {
|
||||
$match = static::extractEntityIdFromAutocompleteInput($input);
|
||||
if ($match === NULL) {
|
||||
// Try to get a match from the input string when the user didn't use
|
||||
// the autocomplete but filled in a value manually.
|
||||
$match = static::matchEntityByTitle($handler, $input, $element, $form_state, !$autocreate);
|
||||
}
|
||||
|
||||
if ($match !== NULL) {
|
||||
$value[] = array(
|
||||
'target_id' => $match,
|
||||
);
|
||||
}
|
||||
elseif ($autocreate) {
|
||||
/** @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionWithAutocreateInterface $handler */
|
||||
// Auto-create item. See an example of how this is handled in
|
||||
// \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::presave().
|
||||
$value[] = array(
|
||||
'entity' => $handler->createNewEntity($element['#target_type'], $element['#autocreate']['bundle'], $input, $element['#autocreate']['uid']),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class Name extends InOperator {
|
|||
'#target_type' => 'user',
|
||||
'#tags' => TRUE,
|
||||
'#default_value' => $default_value,
|
||||
'#process_default_value' => FALSE,
|
||||
'#process_default_value' => $this->isExposed(),
|
||||
);
|
||||
|
||||
$user_input = $form_state->getUserInput();
|
||||
|
|
|
@ -137,6 +137,17 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
|||
$this->drupalGet($path, $options);
|
||||
$this->assertRaw(t('There are no entities matching "%value".', array('%value' => implode(', ', $users))));
|
||||
|
||||
// Pass in an invalid target_id in for the entity_autocomplete value format.
|
||||
// There should be no errors, but all results should be returned as the
|
||||
// default value for the autocomplete will not match any users so should
|
||||
// be empty.
|
||||
$options['query']['uid'] = [['target_id' => 9999]];
|
||||
$this->drupalGet($path, $options);
|
||||
// The actual result should contain all of the user ids.
|
||||
foreach ($this->accounts as $account) {
|
||||
$this->assertRaw($account->id());
|
||||
}
|
||||
|
||||
// Pass in an invalid username and a valid username.
|
||||
$users = array($this->randomMachineName(), $this->names[0]);
|
||||
$users = array_map('strtolower', $users);
|
||||
|
@ -156,6 +167,18 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
|||
foreach ($this->accounts as $account) {
|
||||
$this->assertRaw($account->id());
|
||||
}
|
||||
|
||||
// Pass in just valid user IDs in the entity_autocomplete target_id format.
|
||||
$options['query']['uid'] = array_map(function($account) {
|
||||
return ['target_id' => $account->id()];
|
||||
}, $this->accounts);
|
||||
|
||||
$this->drupalGet($path, $options);
|
||||
$this->assertNoRaw('Unable to find user');
|
||||
// The actual result should contain all of the user ids.
|
||||
foreach ($this->accounts as $account) {
|
||||
$this->assertRaw($account->id());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -310,6 +310,31 @@ class EntityAutocompleteElementFormTest extends EntityKernelTestBase implements
|
|||
$this->assertEqual($form['tags_access']['#value'], $expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests ID input is handled correctly.
|
||||
*
|
||||
* E.g. This can happen with GET form parameters.
|
||||
*/
|
||||
public function testEntityAutocompleteIdInput() {
|
||||
/** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
|
||||
$form_builder = $this->container->get('form_builder');
|
||||
//$form = $form_builder->getForm($this);
|
||||
$form_state = (new FormState())
|
||||
->setMethod('GET')
|
||||
->setValues([
|
||||
'single' => [['target_id' => $this->referencedEntities[0]->id()]],
|
||||
'single_no_validate' => [['target_id' => $this->referencedEntities[0]->id()]],
|
||||
]);
|
||||
|
||||
$form_builder->submitForm($this, $form_state);
|
||||
|
||||
$form = $form_state->getCompleteForm();
|
||||
|
||||
$expected_label = $this->getAutocompleteInput($this->referencedEntities[0]);
|
||||
$this->assertSame($expected_label, $form['single']['#value']);
|
||||
$this->assertSame($expected_label, $form['single_no_validate']['#value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an entity label in the format needed by the EntityAutocomplete
|
||||
* element.
|
||||
|
|
Loading…
Reference in New Issue