Issue #2718697 by damiankloip, dawehner: EntityAutocomplete element cannot handle GET input values

8.2.x
Alex Pott 2016-05-08 12:55:05 -05:00
parent 853202a000
commit 677116e149
4 changed files with 99 additions and 28 deletions

View File

@ -57,13 +57,14 @@ 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)) {
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.');
}
@ -73,6 +74,19 @@ class EntityAutocomplete extends Textfield {
}
}
// 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);
}
}
/**
* Adds entity autocomplete functionality to a form element.
*
@ -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,7 +161,14 @@ class EntityAutocomplete extends Textfield {
$handler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options);
$autocreate = (bool) $element['#autocreate'] && $handler instanceof SelectionWithAutocreateInterface;
// 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']);
foreach ($input_values as $input) {
$match = static::extractEntityIdFromAutocompleteInput($input);
if ($match === NULL) {
@ -169,6 +191,7 @@ class EntityAutocomplete extends Textfield {
);
}
}
}
// Check that the referenced entities are valid, if needed.
if ($element['#validate_reference'] && !empty($value)) {

View File

@ -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();

View File

@ -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());
}
}
}

View File

@ -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.