Skip to content
Snippets Groups Projects
Commit 677116e1 authored by Alex Pott's avatar Alex Pott
Browse files

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

parent 853202a0
No related branches found
No related tags found
No related merge requests found
......@@ -57,19 +57,33 @@ public static function valueCallback(&$element, $input, FormStateInterface $form
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 @@ public static function processEntityAutocomplete(array &$element, FormStateInter
*/
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 @@ public static function validateEntityAutocomplete(array &$element, FormStateInte
$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']);
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']),
);
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 @@ protected function valueForm(&$form, FormStateInterface $form_state) {
'#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 @@ public function testExposedFilter() {
$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 @@ public function testExposedFilter() {
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 @@ public function testEntityAutocompleteAccess() {
$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.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment