/** * Tests autocompletion edge cases with slashes in the names. */ function testEntityReferenceAutocompletion() { // Add an entity with a slash in its name. $entity_1 = $this->container->get('entity_type.manager')->getStorage($this->entityType)->create(array('name' => '10/16/2011')); $entity_1->save(); // Add another entity that differs after the slash character. $entity_2 = $this->container->get('entity_type.manager')->getStorage($this->entityType)->create(array('name' => '10/17/2011')); $entity_2->save(); // Add another entity that has both a comma, a slash and markup. $entity_3 = $this->container->get('entity_type.manager')->getStorage($this->entityType)->create(array('name' => 'label with, and / test')); $entity_3->save(); // Try to autocomplete a entity label that matches both entities. // We should get both entities in a JSON encoded string. $input = '10/'; $data = $this->getAutocompleteResult($input); $this->assertIdentical($data[0]['label'], Html::escape($entity_1->name->value), 'Autocomplete returned the first matching entity'); $this->assertIdentical($data[1]['label'], Html::escape($entity_2->name->value), 'Autocomplete returned the second matching entity'); // Try to autocomplete a entity label that matches the first entity. // We should only get the first entity in a JSON encoded string. $input = '10/16'; $data = $this->getAutocompleteResult($input); $target = array('value' => $entity_1->name->value . ' (1)', 'label' => Html::escape($entity_1->name->value)); $this->assertIdentical(reset($data), $target, 'Autocomplete returns only the expected matching entity.'); // Try to autocomplete a entity label that matches the second entity, and // the first entity is already typed in the autocomplete (tags) widget. $input = $entity_1->name->value . ' (1), 10/17'; $data = $this->getAutocompleteResult($input); $this->assertIdentical($data[0]['label'], Html::escape($entity_2->name->value), 'Autocomplete returned the second matching entity'); // Try to autocomplete a entity label with both a comma, a slash and markup. $input = '"label with, and /"'; $data = $this->getAutocompleteResult($input); $n = $entity_3->name->value . ' (3)'; // Entity labels containing commas or quotes must be wrapped in quotes. $n = Tags::encode($n); $target = array('value' => $n, 'label' => Html::escape($entity_3->name->value)); $this->assertIdentical(reset($data), $target, 'Autocomplete returns an entity label containing a comma and a slash.'); }
/** * Returns matched labels based on a given search string. * * @param string $target_type * The ID of the target entity type. * @param string $selection_handler * The plugin ID of the entity reference selection handler. * @param array $selection_settings * An array of settings that will be passed to the selection handler. * @param string $string * (optional) The label of the entity to query by. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Thrown when the current user doesn't have access to the specifies entity. * * @return array * An array of matched entity labels, in the format required by the AJAX * autocomplete API (e.g. array('value' => $value, 'label' => $label)). * * @see \Drupal\system\Controller\EntityAutocompleteController */ public function getMatches($target_type, $selection_handler, $selection_settings, $string = '') { $matches = array(); $options = array('target_type' => $target_type, 'handler' => $selection_handler, 'handler_settings' => $selection_settings); $handler = $this->selectionManager->getInstance($options); if (isset($string)) { // Get an array of matching entities. $match_operator = !empty($selection_settings['match_operator']) ? $selection_settings['match_operator'] : 'CONTAINS'; $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 10); // Loop through the entities and convert them into autocomplete output. foreach ($entity_labels as $values) { foreach ($values as $entity_id => $label) { $key = "{$label} ({$entity_id})"; // Strip things like starting/trailing white spaces, line breaks and // tags. $key = preg_replace('/\\s\\s+/', ' ', str_replace("\n", '', trim(String::decodeEntities(strip_tags($key))))); // Names containing commas or quotes must be wrapped in quotes. $key = Tags::encode($key); $matches[] = array('value' => $key, 'label' => $label); } } } return $matches; }
/** * Gets terms which matches some typed terms. * * @param string $tags_typed * The full typed tags string. * @param array $vids * An array of vocabulary IDs which * @param $tag_last * The lasted typed tag. * * @return array * Returns an array of matching terms. */ protected function getMatchingTerms($tags_typed, array $vids, $tag_last) { $matches = array(); $this->termEntityQuery->addTag('term_access'); // Do not select already entered terms. if (!empty($tags_typed)) { $this->termEntityQuery->condition('name', $tags_typed, 'NOT IN'); } // Select rows that match by term name. $tids = $this->termEntityQuery->condition('vid', $vids, 'IN')->condition('name', $tag_last, 'CONTAINS')->range(0, 10)->execute(); $prefix = count($tags_typed) ? Tags::implode($tags_typed) . ', ' : ''; if (!empty($tids)) { $terms = $this->entityManager->getStorage('taxonomy_term')->loadMultiple(array_keys($tids)); foreach ($terms as $term) { // Term names containing commas or quotes must be wrapped in quotes. $name = Tags::encode($term->getName()); $matches[] = array('value' => $prefix . $name, 'label' => String::checkPlain($term->getName())); } return $matches; } return $matches; }
/** * Converts an array of entity objects into a string of entity labels. * * This method is also responsible for checking the 'view label' access on the * passed-in entities. * * @param \Drupal\Core\Entity\EntityInterface[] $entities * An array of entity objects. * * @return string * A string of entity labels separated by commas. */ public static function getEntityLabels(array $entities) { $entity_labels = array(); foreach ($entities as $entity) { // Use the special view label, since some entities allow the label to be // viewed, even if the entity is not allowed to be viewed. $label = $entity->access('view label') ? $entity->label() : t('- Restricted access -'); // Take into account "autocreated" entities. if (!$entity->isNew()) { $label .= ' (' . $entity->id() . ')'; } // Labels containing commas or quotes must be wrapped in quotes. $entity_labels[] = Tags::encode($label); } return implode(', ', $entity_labels); }
/** * Tests term autocompletion edge cases with slashes in the names. */ function testTermAutocompletion() { // Add a term with a slash in the name. $first_term = $this->createTerm($this->vocabulary); $first_term->setName('10/16/2011'); $first_term->save(); // Add another term that differs after the slash character. $second_term = $this->createTerm($this->vocabulary); $second_term->setName('10/17/2011'); $second_term->save(); // Add another term that has both a comma and a slash character. $third_term = $this->createTerm($this->vocabulary); $third_term->setName('term with, a comma and / a slash'); $third_term->save(); // Try to autocomplete a term name that matches both terms. // We should get both terms in a json encoded string. $input = '10/'; $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); // The result order is not guaranteed, so check each term separately. $result = $this->drupalGet($path, array('query' => array('q' => $input))); // Pull the label properties from the array of arrays. $data = Json::decode($result); $data = array_map(function ($item) { return $item['label']; }, $data); $this->assertTrue(in_array(String::checkPlain($first_term->getName()), $data), 'Autocomplete returned the first matching term'); $this->assertTrue(in_array(String::checkPlain($second_term->getName()), $data), 'Autocomplete returned the second matching term'); // Try to autocomplete a term name that matches first term. // We should only get the first term in a json encoded string. $input = '10/16'; $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); $this->drupalGet($path, array('query' => array('q' => $input))); $target = array(array('value' => String::checkPlain($first_term->getName()), 'label' => $first_term->getName())); $this->assertRaw(Json::encode($target), 'Autocomplete returns only the expected matching term.'); // Try to autocomplete a term name with both a comma and a slash. $input = '"term with, comma and / a'; $path = 'taxonomy/autocomplete/node/taxonomy_' . $this->vocabulary->id(); $this->drupalGet($path, array('query' => array('q' => $input))); // Term names containing commas or quotes must be wrapped in quotes. $n = Tags::encode($third_term->getName()); $target = array(array('value' => $n, 'label' => String::checkPlain($third_term->getName()))); $this->assertRaw(Json::encode($target), 'Autocomplete returns a term containing a comma and a slash.'); }
/** * Gets the entity labels. */ protected function getLabels(FieldItemListInterface $items, $delta) { if ($items->isEmpty()) { return array(); } $entity_labels = array(); // Load those entities and loop through them to extract their labels. $entities = entity_load_multiple($this->getFieldSetting('target_type'), $this->getEntityIds($items, $delta)); foreach ($entities as $entity_id => $entity_item) { $label = $entity_item->label(); $key = "{$label} ({$entity_id})"; // Labels containing commas or quotes must be wrapped in quotes. $key = Tags::encode($key); $entity_labels[] = $key; } return $entity_labels; }
/** * Converts an array of entity objects into a string of entity labels. * * This method is also responsible for checking the 'view' access on the * passed-in entities. * * @param \Drupal\Core\Entity\EntityInterface[] $entities * An array of entity objects. * * @return string * A string of entity labels separated by commas. */ public static function getEntityLabels(array $entities) { $entity_labels = array(); foreach ($entities as $entity) { $label = $entity->access('view') ? $entity->label() : t('- Restricted access -'); // Take into account "autocreated" entities. if (!$entity->isNew()) { $label .= ' (' . $entity->id() . ')'; } // Labels containing commas or quotes must be wrapped in quotes. $entity_labels[] = Tags::encode($label); } return implode(', ', $entity_labels); }
/** * Returns matched labels based on a given field, instance and search string. * * This function can be used by other modules that wish to pass a mocked * definition of the field on instance. * * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * The field definition. * @param string $entity_type * The entity type. * @param string $bundle * The entity bundle. * @param string $entity_id * (optional) The entity ID the entity reference field is attached to. * Defaults to ''. * @param string $prefix * (optional) A prefix for all the keys returned by this function. * @param string $string * (optional) The label of the entity to query by. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Thrown when the current user doesn't have access to the specifies entity. * * @return array * A list of matched entity labels. * * @see \Drupal\entity_reference\EntityReferenceController */ public function getMatches(FieldDefinitionInterface $field_definition, $entity_type, $bundle, $entity_id = '', $prefix = '', $string = '') { $matches = array(); $entity = NULL; if ($entity_id !== 'NULL') { $entity = $this->entityManager->getStorage($entity_type)->load($entity_id); if (!$entity || !$entity->access('view')) { throw new AccessDeniedHttpException(); } } $handler = $this->selectionHandlerManager->getSelectionHandler($field_definition, $entity); if (isset($string)) { // Get an array of matching entities. $widget = entity_get_form_display($entity_type, $bundle, 'default')->getComponent($field_definition->getName()); $match_operator = !empty($widget['settings']['match_operator']) ? $widget['settings']['match_operator'] : 'CONTAINS'; $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 10); // Loop through the entities and convert them into autocomplete output. foreach ($entity_labels as $values) { foreach ($values as $entity_id => $label) { $key = "{$label} ({$entity_id})"; // Strip things like starting/trailing white spaces, line breaks and // tags. $key = preg_replace('/\\s\\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key))))); // Names containing commas or quotes must be wrapped in quotes. $key = Tags::encode($key); $matches[] = array('value' => $prefix . $key, 'label' => $label); } } } return $matches; }