From 7bf6d57a5b30fc59eb441237619d082204697834 Mon Sep 17 00:00:00 2001 From: Vyacheslav Malchik Date: Mon, 22 Jul 2019 19:22:00 +0500 Subject: [PATCH 1/2] #2937914: - add tab for taxonomy term - create page to manage subqueues of term - override entity autocomplete to select only content from term --- entityqueue_taxonomy.info.yml | 6 +- entityqueue_taxonomy.links.contextual.yml | 5 + entityqueue_taxonomy.links.task.yml | 5 + entityqueue_taxonomy.module | 72 ++++++++- entityqueue_taxonomy.routing.yml | 21 +++ entityqueue_taxonomy.services.yml | 4 + ...ityQueueTaxonomyAutocompleteController.php | 70 +++++++++ .../EntityQueueTaxonomyUIController.php | 148 ++++++++++++++++++ ...EntityQueueTaxonomyAutocompleteMatcher.php | 50 ++++++ src/Plugin/EntityQueueHandler/Taxonomy.php | 39 +++-- .../EntityQueueTaxonomyNodeSelection.php | 98 ++++++++++++ .../views/argument_default/QueueNameTerm.php | 19 ++- 12 files changed, 514 insertions(+), 23 deletions(-) create mode 100644 entityqueue_taxonomy.links.contextual.yml create mode 100644 entityqueue_taxonomy.links.task.yml create mode 100644 entityqueue_taxonomy.routing.yml create mode 100644 entityqueue_taxonomy.services.yml create mode 100644 src/Controller/EntityQueueTaxonomyAutocompleteController.php create mode 100644 src/Controller/EntityQueueTaxonomyUIController.php create mode 100644 src/EntityQueueTaxonomyAutocompleteMatcher.php create mode 100644 src/Plugin/EntityReferenceSelection/EntityQueueTaxonomyNodeSelection.php diff --git a/entityqueue_taxonomy.info.yml b/entityqueue_taxonomy.info.yml index d65ab97..ec97417 100644 --- a/entityqueue_taxonomy.info.yml +++ b/entityqueue_taxonomy.info.yml @@ -1,7 +1,7 @@ -name: entityqueue_taxonomy +name: Entityqueue Taxonomy type: module -description: Entityqueue Taxonomy -- smart queues for taxonomy terms +description: Creates entity queue for a taxonomy term. core: 8.x -package: entityqueue +package: Entityqueue dependencies: - entityqueue diff --git a/entityqueue_taxonomy.links.contextual.yml b/entityqueue_taxonomy.links.contextual.yml new file mode 100644 index 0000000..83501cd --- /dev/null +++ b/entityqueue_taxonomy.links.contextual.yml @@ -0,0 +1,5 @@ +entity.taxonomy_term.entityqueue_taxonomy: + title: 'Entity queue' + group: taxonomy_term + route_name: entity.taxonomy_term.entityqueue_taxonomy + weight: 10 diff --git a/entityqueue_taxonomy.links.task.yml b/entityqueue_taxonomy.links.task.yml new file mode 100644 index 0000000..1096bed --- /dev/null +++ b/entityqueue_taxonomy.links.task.yml @@ -0,0 +1,5 @@ +entity.taxonomy_term.entityqueue_taxonomy: + route_name: entity.taxonomy_term.entityqueue_taxonomy + title: 'Entity queue' + base_route: entity.taxonomy_term.canonical + weight: 10 diff --git a/entityqueue_taxonomy.module b/entityqueue_taxonomy.module index 01064fc..02c42da 100644 --- a/entityqueue_taxonomy.module +++ b/entityqueue_taxonomy.module @@ -5,9 +5,14 @@ * Contains entityqueue_taxonomy.module. */ +use Drupal\Component\Utility\Crypt; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\Site\Settings; use Drupal\entityqueue\Entity\EntityQueue; use Drupal\entityqueue\Entity\EntitySubqueue; +use Drupal\taxonomy\TermInterface; +use Drupal\Core\Entity\EntityTypeInterface; /** * Implements hook_help(). @@ -18,7 +23,7 @@ function entityqueue_taxonomy_help($route_name, RouteMatchInterface $route_match case 'help.page.entityqueue_taxonomy': $output = ''; $output .= '

' . t('About') . '

'; - $output .= '

' . t('Entityqueue Taxonomy -- smart queues for taxonomy terms') . '

'; + $output .= '

' . t('Creates entity queue for a taxonomy term.') . '

'; return $output; default: @@ -26,10 +31,10 @@ function entityqueue_taxonomy_help($route_name, RouteMatchInterface $route_match } /** - * Implements hook_ENTITY_TYPE_insert. + * Implements hook_ENTITY_TYPE_insert(). */ -function entityqueue_taxonomy_term_insert(\Drupal\taxonomy\TermInterface $term) { - /** @var EntityQueue $entityqueues */ +function entityqueue_taxonomy_term_insert(TermInterface $term) { + /** @var \Drupal\entityqueue\Entity\EntityQueue[] $entityqueues */ $entityqueues = EntityQueue::loadMultiple(); foreach ($entityqueues as $id => $entityqueue) { if ($entityqueue->getHandler() === 'taxonomy_term') { @@ -46,4 +51,61 @@ function entityqueue_taxonomy_term_insert(\Drupal\taxonomy\TermInterface $term) } } } -} \ No newline at end of file +} + +/** + * Implements hook_form_alter(). + */ +function entityqueue_taxonomy_form_alter(&$form, &$form_state, $form_id) { + if (preg_match('/entity_subqueue_(.*)_edit_form/i', $form_id, $matches)) { + $entityqueue_id = $matches[1]; + $entityqueue = EntityQueue::load($entityqueue_id); + $subqueue_id = $form['name']['#default_value']; + + $element = &$form['items']['widget']['add_more']['new_item']['target_id']; + + $info = \Drupal::service('element_info')->getInfo($element['#type']); + // Overlay $info onto $element, retaining preexisting keys in $element. + $element += $info; + + // Add vocabulary and taxonomy term ID to element to process. + preg_match("/{$entityqueue_id}_(\d+)/i", $subqueue_id, $matches); + $element['#taxonomy_term'] = $matches[1]; + $element['#vocabulary'] = $entityqueue->getHandlerConfiguration()['vocabulary']; + + // Add processing to alter autocomplete route. + $entity_autocomplete_process = $element['#process'][0]; + $element['#process'][0] = 'entityqueue_taxonomy_entity_autocomplete_process'; + array_unshift($element['#process'], $entity_autocomplete_process); + } +} + +/** + * Entityqueue Taxonomy autocomplete element process to alter callback route + * and provide vocabulary and taxonomy term ID. + */ +function entityqueue_taxonomy_entity_autocomplete_process(array &$element) { + $element['#selection_handler'] = str_replace('default', 'entityqueue_taxonomy', $element['#selection_handler']); + + // Store the selection settings in the key/value store and pass a hashed key + // in the route parameters. + $selection_settings = isset($element['#selection_settings']) ? $element['#selection_settings'] : []; + $data = serialize($selection_settings) . $element['#target_type'] . $element['#selection_handler'] . $element['#vocabulary'] . $element['#taxonomy_term']; + $selection_settings_key = Crypt::hmacBase64($data, Settings::getHashSalt()); + + $key_value_storage = \Drupal::keyValue('entity_autocomplete'); + if (!$key_value_storage->has($selection_settings_key)) { + $key_value_storage->set($selection_settings_key, $selection_settings); + } + + $element['#autocomplete_route_name'] = 'entityqueue_taxonomy.entity_autocomplete'; + $element['#autocomplete_route_parameters'] = [ + 'target_type' => $element['#target_type'], + 'selection_handler' => $element['#selection_handler'], + 'vocabulary' => $element['#vocabulary'], + 'taxonomy_term' => $element['#taxonomy_term'], + 'selection_settings_key' => $selection_settings_key, + ]; + + return $element; +} diff --git a/entityqueue_taxonomy.routing.yml b/entityqueue_taxonomy.routing.yml new file mode 100644 index 0000000..f4c623e --- /dev/null +++ b/entityqueue_taxonomy.routing.yml @@ -0,0 +1,21 @@ +entity.taxonomy_term.entityqueue_taxonomy: + path: '/taxonomy/term/{taxonomy_term}/entityqueue-taxonomy' + defaults: + _controller: '\Drupal\entityqueue_taxonomy\Controller\EntityQueueTaxonomyUIController::taxonomyTermSubqueues' + entity_type_id: taxonomy_term + _title: 'Taxonomy entity queue' + options: + _admin_route: TRUE + parameters: + taxonomy_term: + type: entity:taxonomy_term + requirements: + _custom_access: '\Drupal\entityqueue_taxonomy\Controller\EntityQueueTaxonomyUIController::access' + taxonomy_term: \d+ + +entityqueue_taxonomy.entity_autocomplete: + path: '/entityqueue_taxonomy_autocomplete/{target_type}/{selection_handler}/{vocabulary}/{taxonomy_term}/{selection_settings_key}' + defaults: + _controller: '\Drupal\entityqueue_taxonomy\Controller\EntityQueueTaxonomyAutocompleteController::handleAutocomplete' + requirements: + _access: 'TRUE' diff --git a/entityqueue_taxonomy.services.yml b/entityqueue_taxonomy.services.yml new file mode 100644 index 0000000..d1c740e --- /dev/null +++ b/entityqueue_taxonomy.services.yml @@ -0,0 +1,4 @@ +services: + entityqueue_taxonomy.autocomplete_matcher: + class: Drupal\entityqueue_taxonomy\EntityQueueTaxonomyAutocompleteMatcher + arguments: ['@plugin.manager.entity_reference_selection'] diff --git a/src/Controller/EntityQueueTaxonomyAutocompleteController.php b/src/Controller/EntityQueueTaxonomyAutocompleteController.php new file mode 100644 index 0000000..0281030 --- /dev/null +++ b/src/Controller/EntityQueueTaxonomyAutocompleteController.php @@ -0,0 +1,70 @@ +get('entityqueue_taxonomy.autocomplete_matcher'), + $container->get('keyvalue')->get('entity_autocomplete') + ); + } + + /** + * {@inheritdoc} + */ + public function handleAutocomplete(Request $request, $target_type, $selection_handler, $selection_settings_key, $vocabulary = NULL, $taxonomy_term = NULL) { + $matches = []; + // Get the typed string from the URL, if it exists. + if ($input = $request->query->get('q')) { + $typed_string = Tags::explode($input); + $typed_string = mb_strtolower(array_pop($typed_string)); + + // Selection settings are passed in as a hashed key of a serialized array + // stored in the key/value store. + $selection_settings = $this->keyValue->get($selection_settings_key, FALSE); + if ($selection_settings !== FALSE) { + $selection_settings_hash = Crypt::hmacBase64(serialize($selection_settings) . $target_type . $selection_handler . $vocabulary . $taxonomy_term, Settings::getHashSalt()); + if ($selection_settings_hash !== $selection_settings_key) { + // Disallow access when the selection settings hash does not match the + // passed-in key. + throw new AccessDeniedHttpException('Invalid selection settings key.'); + } + } + else { + // Disallow access when the selection settings key is not found in the + // key/value store. + throw new AccessDeniedHttpException(); + } + + // Provide tvocabulary and taxonomy term ID to matcher. + $matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string, $vocabulary, $taxonomy_term); + } + + return new JsonResponse($matches); + } + +} diff --git a/src/Controller/EntityQueueTaxonomyUIController.php b/src/Controller/EntityQueueTaxonomyUIController.php new file mode 100644 index 0000000..ac439df --- /dev/null +++ b/src/Controller/EntityQueueTaxonomyUIController.php @@ -0,0 +1,148 @@ +entityTypeManager()->getStorage('entity_subqueue')->create( + [ + 'queue' => $entity_queue->id(), + 'name' => $entity_queue->id() . '_' . $taxonomy_term->id(), + 'title' => $taxonomy_term->label(), + 'langcode' => $entity_queue->language()->getId(), + ]); + return $this->entityFormBuilder()->getForm($subqueue); + } + + /** + * Returns a list of subqueues for the term. + * + * @param \Drupal\taxonomy\TermInterface $taxonomy_term + * The taxonomy term. + * + * @return array + * The term subqueues list. + */ + public function taxonomyTermSubqueues(TermInterface $taxonomy_term) { + $rows = []; + $queues = $this->getAvailableTaxonomyQueuesForEntity($this->currentUser()); + $storage = $this->entityTypeManager->getStorage('entity_subqueue'); + + $destination = Url::fromRoute("entity.taxonomy_term.entityqueue_taxonomy", ['taxonomy_term' => $taxonomy_term->id()])->toString(); + + foreach ($queues as $queue) { + if ($subqueue = $storage->load($queue->id() . '_' . $taxonomy_term->id())) { + $title = $this->t('Edit subqueue items'); + $url = $subqueue->toUrl('edit-form', ['query' => ['destination' => $destination]]); + $operations = [ + 'data' => [ + '#type' => 'operations', + '#links' => [ + 'edit' => [ + 'title' => $title, + 'url' => $url, + ], + ], + ], + ]; + } + else { + $operations = $this->t('N/A'); + } + + $rows[] = [ + $queue->label(), + $operations, + ]; + } + + return [ + '#type' => 'table', + '#rows' => $rows, + '#header' => [ + $this->t('Subqueue'), + $this->t('Operations'), + ], + ]; + + } + + /** + * Checks access for a specific request. + * + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * @param \Drupal\Core\Session\AccountInterface $account + * The account to check access. + * @param string $entity_type_id + * (optional) The entity type ID. + * + * @return \Drupal\Core\Access\AccessResultInterface + * The access result. + */ + public function access(RouteMatchInterface $route_match, AccountInterface $account, $entity_type_id = NULL) { + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = $route_match->getParameter($entity_type_id); + + $permisssion = 'update ' . $entity->bundle() . ' entityqueue'; + + if (!$account->hasPermission($permisssion)) { + return AccessResult::forbidden(); + } + + if ($entity && $this->getAvailableTaxonomyQueuesForEntity($account)) { + return AccessResult::allowed(); + } + + return AccessResult::forbidden(); + } + + /** + * Gets a list of queues which can hold this entity. + * + * @param \Drupal\Core\Session\AccountInterface $account + * The account to check access. + * + * @return \Drupal\entityqueue\EntityQueueInterface[] + * An array of entity queues which can hold this entity. + */ + protected function getAvailableTaxonomyQueuesForEntity(AccountInterface $account) { + $storage = $this->entityTypeManager()->getStorage('entity_queue'); + + $queues = []; + /** @var \Drupal\entityqueue\Entity\EntityQueue[] $entityqueues */ + $entityqueues = $storage->loadMultiple(); + + foreach ($entityqueues as $id => $entityqueue) { + if ($entityqueue->getHandler() === 'taxonomy_term' && $entityqueue->access('update', $account)) { + $queues[$entityqueue->id()] = $entityqueue; + } + } + + return $queues; + } + +} diff --git a/src/EntityQueueTaxonomyAutocompleteMatcher.php b/src/EntityQueueTaxonomyAutocompleteMatcher.php new file mode 100644 index 0000000..ab14be7 --- /dev/null +++ b/src/EntityQueueTaxonomyAutocompleteMatcher.php @@ -0,0 +1,50 @@ + $target_type, + 'handler' => $selection_handler, + ]; + + /** @var \Drupal\entityqueue_taxonomy\Plugin\EntityReferenceSelection\EntityQueueTaxonomyNodeSelection $handler */ + $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, $vocabulary, $taxonomy_term); + + // 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(Html::decodeEntities(strip_tags($key))))); + // Names containing commas or quotes must be wrapped in quotes. + $key = Tags::encode($key); + $matches[] = ['value' => $key, 'label' => $label]; + } + } + } + + return $matches; + } + +} diff --git a/src/Plugin/EntityQueueHandler/Taxonomy.php b/src/Plugin/EntityQueueHandler/Taxonomy.php index 0112f0a..0beb324 100644 --- a/src/Plugin/EntityQueueHandler/Taxonomy.php +++ b/src/Plugin/EntityQueueHandler/Taxonomy.php @@ -2,8 +2,6 @@ namespace Drupal\entityqueue_taxonomy\Plugin\EntityQueueHandler; - -use Drupal\Core\Database\TransactionNameNonUniqueException; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; @@ -23,11 +21,12 @@ class Taxonomy extends Multiple implements ContainerFactoryPluginInterface { /** - * Drupal\Core\Entity\EntityTypeManager definition. + * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; + /** * Constructs a new Taxonomy object. * @@ -37,6 +36,8 @@ class Taxonomy extends Multiple implements ContainerFactoryPluginInterface { * The plugin_id for the plugin instance. * @param string $plugin_definition * The plugin implementation definition. + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. */ public function __construct( array $configuration, @@ -47,6 +48,7 @@ public function __construct( parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager); $this->entityTypeManager = $entity_type_manager; } + /** * {@inheritdoc} */ @@ -59,6 +61,9 @@ public static function create(ContainerInterface $container, array $configuratio ); } + /** + * @inheritdoc + */ public function defaultConfiguration() { $config = parent::defaultConfiguration() + [ 'vocabulary' => NULL, @@ -66,6 +71,9 @@ public function defaultConfiguration() { return $config; } + /** + * @inheritdoc + */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $vocabularies = Vocabulary::loadMultiple(); $options = array_map(function($element){ @@ -78,15 +86,14 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#options' => $options, '#default_value' => $this->configuration['vocabulary'], ]; - return parent::buildConfigurationForm($form, $form_state); // TODO: Change the autogenerated stub + return parent::buildConfigurationForm($form, $form_state); } public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { parent::submitConfigurationForm($form, $form_state); if (!$form_state->getErrors()) { - $values = $form_state->getValue($form['#parents']); - $this->configuration['vocabulary'] = $values['vocabulary']; + $this->configuration['vocabulary'] = $form_state->getValue('vocabulary'); } } @@ -97,6 +104,9 @@ public function hasAutomatedSubqueues() { return TRUE; } + /** + * @inheritdoc + */ public function onQueuePostSave(EntityQueueInterface $queue, EntityStorageInterface $storage, $update = TRUE) { parent::onQueuePostSave($queue, $storage, $update); @@ -108,7 +118,8 @@ public function onQueuePostSave(EntityQueueInterface $queue, EntityStorageInterf foreach ($subqueues as $subqueue_index => $subqueue) { if (in_array($subqueue->id(), array_keys($terms))) { unset($terms[$subqueue->id()]); - } else { + } + else { $subqueue->delete(); } } @@ -122,7 +133,6 @@ public function onQueuePostSave(EntityQueueInterface $queue, EntityStorageInterf 'langcode' => $queue->language()->getId(), ]); $subqueue->save(); - } } @@ -138,9 +148,18 @@ public function onQueuePostDelete(EntityQueueInterface $queue, EntityStorageInte $subqueue_storage->delete($subqueues); } - + /** + * Get subqueues of the queue. + * + * @param EntityQueueInterface $queue + * The queue object. + * + * @return array + * An array of subqueues. + */ public function getSubqueues(EntityQueueInterface $queue) { - // Run an entity query to get all taxonomy terms in the vocabulary found in the $queue's settings + // Run an entity query to get all taxonomy terms in the vocabulary found + // in the $queue's settings. $subqueues = []; $vocabulary = $this->configuration['vocabulary']; /** @var \Drupal\taxonomy\TermStorageInterface $storage */ diff --git a/src/Plugin/EntityReferenceSelection/EntityQueueTaxonomyNodeSelection.php b/src/Plugin/EntityReferenceSelection/EntityQueueTaxonomyNodeSelection.php new file mode 100644 index 0000000..256bb56 --- /dev/null +++ b/src/Plugin/EntityReferenceSelection/EntityQueueTaxonomyNodeSelection.php @@ -0,0 +1,98 @@ +getConfiguration()['target_type']; + $configuration = $this->getConfiguration(); + $bundles = $configuration['target_bundles']; + $taxonomy_fields = []; + + foreach ($bundles as $bundle) { + /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */ + $field_manager = \Drupal::service('entity_field.manager'); + $fields = $field_manager->getFieldDefinitions($target_type, $bundle); + // Get all taxonomy fields of entity type. + $taxonomy_fields += $this->getTaxonomyFields($fields, $vocabulary); + } + + $query = $this->buildEntityQuery($match, $match_operator); + + if ($taxonomy_fields) { + // Add found fields to 'or' condition. + $or = $query->orConditionGroup(); + foreach ($taxonomy_fields as $field_name => $field) { + $or->condition($field_name, $taxonomy_term); + } + $query->condition($or); + } + + if ($limit > 0) { + $query->range(0, $limit); + } + + $result = $query->execute(); + + if (empty($result)) { + return []; + } + + $options = []; + $entities = $this->entityTypeManager->getStorage($target_type)->loadMultiple($result); + foreach ($entities as $entity_id => $entity) { + $bundle = $entity->bundle(); + $options[$bundle][$entity_id] = Html::escape($this->entityRepository->getTranslationFromContext($entity)->label()); + } + + return $options; + } + + /** + * Get taxonomy entity reference fields for the vocabulary. + * + * @param \Drupal\Core\Field\FieldDefinitionInterface[] $fields + * List of field definitions. + * @param string $vocabulary + * The vocabulary ID. + * + * @return \Drupal\Core\Field\FieldDefinitionInterface[] + * Array of taxonomy term entity reference fields for vocabulary. + */ + protected function getTaxonomyFields(array $fields, $vocabulary) { + $result = []; + foreach ($fields as $field_name => $field) { + if ($field->getType() !== 'entity_reference' || $field->getSetting('handler') !== 'default:taxonomy_term') { + continue; + } + + $handler_settings = $field->getSetting('handler_settings'); + if (!in_array($vocabulary, $handler_settings['target_bundles'])) { + continue; + } + + $result[$field_name] = $field; + } + + return $result; + } + +} diff --git a/src/Plugin/views/argument_default/QueueNameTerm.php b/src/Plugin/views/argument_default/QueueNameTerm.php index 965faba..b5f45b3 100644 --- a/src/Plugin/views/argument_default/QueueNameTerm.php +++ b/src/Plugin/views/argument_default/QueueNameTerm.php @@ -6,7 +6,6 @@ use Drupal\entityqueue\Entity\EntityQueue; use Drupal\taxonomy\Plugin\views\argument_default\Tid; - /** * @ViewsArgumentDefault( * id = "entityqueue_name_term", @@ -15,6 +14,9 @@ */ class QueueNameTerm extends Tid { + /** + * @inheritdoc + */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { parent::buildOptionsForm($form, $form_state); // We cannot handle multiple terms... @@ -36,19 +38,26 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { ]; } + /** + * @inheritdoc + */ public function defineOptions() { $options = parent::defineOptions(); - // don't need anyall - unset ($options['anyall']); - // do need queue name - $options['entityqueue'] = ['default' => null]; + // Don't need anyall. + unset($options['anyall']); + // Do need queue name. + $options['entityqueue'] = ['default' => NULL]; return $options; } + /** + * @inheritdoc + */ public function getArgument() { $tid = parent::getArgument(); $queue = $this->options['entityqueue']; return $queue . '_' . $tid; } + } From 460bd617860c89525d6de33306cfc57a73f9fd24 Mon Sep 17 00:00:00 2001 From: Vyacheslav Malchik Date: Wed, 7 Aug 2019 18:36:08 +0500 Subject: [PATCH 2/2] Add translation link to subqueue list of term --- .../EntityQueueTaxonomyUIController.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Controller/EntityQueueTaxonomyUIController.php b/src/Controller/EntityQueueTaxonomyUIController.php index ac439df..58e7a49 100644 --- a/src/Controller/EntityQueueTaxonomyUIController.php +++ b/src/Controller/EntityQueueTaxonomyUIController.php @@ -54,23 +54,29 @@ public function taxonomyTermSubqueues(TermInterface $taxonomy_term) { $destination = Url::fromRoute("entity.taxonomy_term.entityqueue_taxonomy", ['taxonomy_term' => $taxonomy_term->id()])->toString(); foreach ($queues as $queue) { + /** @var \Drupal\entityqueue\EntitySubqueueInterface $subqueue */ if ($subqueue = $storage->load($queue->id() . '_' . $taxonomy_term->id())) { - $title = $this->t('Edit subqueue items'); - $url = $subqueue->toUrl('edit-form', ['query' => ['destination' => $destination]]); $operations = [ 'data' => [ '#type' => 'operations', '#links' => [ 'edit' => [ - 'title' => $title, - 'url' => $url, + 'title' => $this->t('Edit subqueue items'), + 'url' => $subqueue->toUrl('edit-form', ['query' => ['destination' => $destination]]), ], ], ], ]; + + if ($subqueue->isTranslatable()) { + $operations['data']['#links']['translate'] = [ + 'title' => $this->t('Translate'), + 'url' => $subqueue->toUrl('drupal:content-translation-overview', ['query' => ['destination' => $destination]]), + ]; + } } else { - $operations = $this->t('N/A'); + continue; } $rows[] = [