From d6c1f31b120ff4e52dc2d0d46e5fe61269aef51d Mon Sep 17 00:00:00 2001 From: Yousef Bajawi Date: Mon, 7 Nov 2016 17:57:21 +0200 Subject: [PATCH] Option to create Entityqueue tab on Entity pages --- entityqueue.links.task.yml | 3 + entityqueue.routing.yml | 18 +++++ entityqueue.services.yml | 6 ++ src/Controller/EntityQueueUIController.php | 95 ++++++++++++++++++++++++++ src/Entity/EntitySubqueue.php | 33 ++++++++- src/Plugin/Derivative/EntityqueueLocalTask.php | 76 +++++++++++++++++++++ src/Routing/RouteSubscriber.php | 95 ++++++++++++++++++++++++++ 7 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 entityqueue.links.task.yml create mode 100644 src/Plugin/Derivative/EntityqueueLocalTask.php create mode 100644 src/Routing/RouteSubscriber.php diff --git a/entityqueue.links.task.yml b/entityqueue.links.task.yml new file mode 100644 index 0000000..5989157 --- /dev/null +++ b/entityqueue.links.task.yml @@ -0,0 +1,3 @@ +entityqueue.entities: + class: \Drupal\Core\Menu\LocalTaskDefault + deriver: \Drupal\entityqueue\Plugin\Derivative\EntityqueueLocalTask diff --git a/entityqueue.routing.yml b/entityqueue.routing.yml index a5afbd4..813558e 100644 --- a/entityqueue.routing.yml +++ b/entityqueue.routing.yml @@ -63,3 +63,21 @@ entity.entity_subqueue.add_form: _title: 'Add subqueue' requirements: _entity_create_access: 'entity_subqueue:{entity_queue}' + +entity.entity_subqueue.add: + path: '/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/{entity}/add' + defaults: + _controller: '\Drupal\entityqueue\Controller\EntityQueueUIController::subqueueAjaxOperation' + op: add + requirements: + _permission: 'administer entityqueue+manipulate entityqueues+manipulate all entityqueues' + _csrf_token: 'TRUE' + +entity.entity_subqueue.remove: + path: '/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/{entity}/remove' + defaults: + _controller: '\Drupal\entityqueue\Controller\EntityQueueUIController::subqueueAjaxOperation' + op: remove + requirements: + _permission: 'administer entityqueue+manipulate entityqueues+manipulate all entityqueues' + _csrf_token: 'TRUE' diff --git a/entityqueue.services.yml b/entityqueue.services.yml index 4d88935..aceb26f 100644 --- a/entityqueue.services.yml +++ b/entityqueue.services.yml @@ -2,3 +2,9 @@ services: plugin.manager.entityqueue.handler: class: Drupal\entityqueue\EntityQueueHandlerManager arguments: ['@container.namespaces', '@cache.default', '@module_handler'] + + entityqueue.route_subscriber: + class: Drupal\entityqueue\Routing\RouteSubscriber + arguments: ['@entity_type.manager'] + tags: + - { name: event_subscriber } \ No newline at end of file diff --git a/src/Controller/EntityQueueUIController.php b/src/Controller/EntityQueueUIController.php index 58be72f..4982d82 100644 --- a/src/Controller/EntityQueueUIController.php +++ b/src/Controller/EntityQueueUIController.php @@ -4,9 +4,14 @@ namespace Drupal\entityqueue\Controller; use Drupal\Core\Controller\ControllerBase; use Drupal\entityqueue\EntityQueueInterface; +use Drupal\entityqueue\EntitySubqueueInterface; use Symfony\Component\HttpFoundation\Request; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; +use Drupal\Core\Ajax\RedirectCommand; +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\entityqueue\Entity\EntityQueue; +use Drupal\entityqueue\Entity\EntitySubqueue; /** * Returns responses for Views UI routes. @@ -30,6 +35,72 @@ class EntityQueueUIController extends ControllerBase { } /** + * Builds the entity add to subqueues page. + * + * @param \Drupal\Core\Routing\RouteMatchInterface $route_match + * The route match. + * @param string $entity_type_id + * (optional) The entity type ID. + * @return array + * Array of page elements to render. + */ + public function entitySubqueueList(RouteMatchInterface $route_match, $entity_type_id = NULL) { + $entity = $route_match->getParameter($entity_type_id); + $subqueues = EntitySubqueue::loadMultiple(); + $list_builder = $this->entityTypeManager()->getListBuilder('entity_queue'); + + $build['#type'] = 'container'; + $build['#attributes']['id'] = 'entity-queue-list'; + $build['#attached']['library'][] = 'core/drupal.ajax'; + $build['table'] = array( + '#type' => 'table', + '#attributes' => array( + 'class' => array('entity-queue-listing-table'), + ), + '#header' => $list_builder->buildHeader(), + '#rows' => array(), + '#cache' => [], + ); + + foreach ($subqueues as $subqueue) { + $queue = $subqueue->getQueue(); + $queue_settings = $queue->getEntitySettings(); + $target_bundles = !empty($queue_settings['handler_settings']['target_bundles']) ? $queue_settings['handler_settings']['target_bundles'] : []; + if ($queue_settings['target_type'] == $entity_type_id && (empty($target_bundles) || in_array($entity->bundle(), $target_bundles))) { + $row = $list_builder->buildRow($queue); + // Check if entity is in queue + $subqueue_items = $subqueue->get('items')->getValue(); + if(in_array($entity->id(), array_column($subqueue_items, 'target_id'))) { + $row['data']['operations']['data']['#links'] = [ + 'remove' => [ + 'title' => $this->t('Remove from queue'), + 'url' => $subqueue->urlInfo('remove'), + 'attributes' => [ + 'class' => ['use-ajax'], + ], + ], + ]; + } + else { + $row['data']['operations']['data']['#links'] = [ + 'add' => [ + 'title' => $this->t('Add to queue'), + 'url' => $subqueue->urlInfo('add'), + 'attributes' => [ + 'class' => ['use-ajax'], + ], + ], + ]; + } + $build['table']['#rows'][$queue->id()] = $row; + } + } + $build['table']['#empty'] = $this->t('There are no available queues.'); + + return $build; + } + + /** * Returns a form to add a new subqeue. * * @param \Drupal\entityqueue\EntityQueueInterface $entity_queue @@ -73,4 +144,28 @@ class EntityQueueUIController extends ControllerBase { return $this->redirect('entity.entity_queue.collection'); } + /** + * Calls a method on an entity subqueue page and reloads the page. + * + * @param \Drupal\entityqueue\EntitySubqueueInterface $entity_subqueue + * The view being acted upon. + * @param string $op + * The operation to perform, e.g., 'add' or 'remove'. + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request. + * + * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse + * Either returns a rebuilt listing page as an AJAX response, or redirects + * back to the subqueue page. + */ + public function subqueueAjaxOperation(EntitySubqueueInterface $entity_subqueue, $op, Request $request) { + $entity_id = $request->get('entity'); + // Perform the operation. + $entity_subqueue->$op($entity_id)->save(); + //TODO: change to replace command instead of reload. + $response = new AjaxResponse(); + $response->addCommand(new RedirectCommand('')); + return $response; + } + } diff --git a/src/Entity/EntitySubqueue.php b/src/Entity/EntitySubqueue.php index f69c4ca..dfb3dc5 100644 --- a/src/Entity/EntitySubqueue.php +++ b/src/Entity/EntitySubqueue.php @@ -49,7 +49,9 @@ use Drupal\user\UserInterface; * links = { * "canonical" = "/admin/structure/entityqueue/{entity_queue}", * "edit-form" = "/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}", - * "delete-form" = "/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/delete" + * "delete-form" = "/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/delete", + * "add" = "/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/{entity}/add", + * "remove" = "/admin/structure/entityqueue/{entity_queue}/{entity_subqueue}/{entity}/remove" * }, * constraints = { * "QueueSize" = {} @@ -277,6 +279,28 @@ class EntitySubqueue extends ContentEntityBase implements EntitySubqueueInterfac } /** + * Adds an entity to a subqueue + */ + public function add($entity_id) { + $this->get('items')->appendItem($entity_id); + return $this; + } + + /** + * Removes an entity from a subqueue + */ + public function remove($entity_id) { + $subqueue_items = $this->get('items')->getValue(); + foreach ($subqueue_items as $key => $item) { + if ($item['target_id'] == $entity_id) { + unset($subqueue_items[$key]); + } + } + $this->get('items')->setValue($subqueue_items); + return $this; + } + + /** * Default value callback for 'uid' base field definition. * * @see ::baseFieldDefinitions() @@ -309,7 +333,12 @@ class EntitySubqueue extends ContentEntityBase implements EntitySubqueueInterfac // The 'entity_queue' parameter is needed by the subqueue routes, so we need // to add it manually. $url->setRouteParameter('entity_queue', $this->bundle()); - + if (in_array($rel, ['add', 'remove'])) { + $route_match = \Drupal::routeMatch(); + $entity_type = $route_match->getParameter('entity_type_id'); + $entity = $route_match->getParameter($entity_type); + $url->setRouteParameter('entity', $entity->id()); + } return $url; } diff --git a/src/Plugin/Derivative/EntityqueueLocalTask.php b/src/Plugin/Derivative/EntityqueueLocalTask.php new file mode 100644 index 0000000..1e4a062 --- /dev/null +++ b/src/Plugin/Derivative/EntityqueueLocalTask.php @@ -0,0 +1,76 @@ +entityManager = $entity_manager; + $this->stringTranslation = $string_translation; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, $base_plugin_id) { + return new static( + $container->get('entity.manager'), + $container->get('string_translation') + ); + } + + /** + * {@inheritdoc} + */ + public function getDerivativeDefinitions($base_plugin_definition) { + $this->derivatives = array(); + + foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) { + if ($entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical')) { + $entityqueue_route_name = "entity.$entity_type_id.entityqueue"; + $this->derivatives[$entityqueue_route_name] = array( + 'entity_type' => $entity_type_id, + 'title' => $this->t('Entityqueue'), + 'route_name' => $entityqueue_route_name, + 'base_route' => "entity.$entity_type_id.canonical", + 'weight' => 999, + ) + $base_plugin_definition; + } + } + + return parent::getDerivativeDefinitions($base_plugin_definition); + } + +} diff --git a/src/Routing/RouteSubscriber.php b/src/Routing/RouteSubscriber.php new file mode 100644 index 0000000..1482831 --- /dev/null +++ b/src/Routing/RouteSubscriber.php @@ -0,0 +1,95 @@ +entityTypeManager = $entity_manager; + } + + /** + * {@inheritdoc} + */ + protected function alterRoutes(RouteCollection $collection) { + foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) { + // Try to get the route from the current collection. + $link_template = $entity_type->getLinkTemplate('canonical'); + if (strpos($link_template, '/') !== FALSE) { + $base_path = '/' . $link_template; + } + else { + if (!$entity_route = $collection->get("entity.$entity_type_id.canonical")) { + continue; + } + $base_path = $entity_route->getPath(); + } + + // Inherit admin route status from edit route, if exists. + $is_admin = FALSE; + $route_name = "entity.$entity_type_id.edit_form"; + if ($edit_route = $collection->get($route_name)) { + $is_admin = (bool) $edit_route->getOption('_admin_route'); + } + + $path = $base_path . '/entityqueue'; + + $route = new Route( + $path, + array( + '_controller' => '\Drupal\entityqueue\Controller\EntityQueueUIController::entitySubqueueList', + 'entity_type_id' => $entity_type_id, + '_title' => 'Entityqueues', + ), + array( + '_permission' => 'administer entityqueue+manipulate entityqueues+manipulate all entityqueues', + ), + array( + 'parameters' => array( + $entity_type_id => array( + 'type' => 'entity:' . $entity_type_id, + ), + ), + '_admin_route' => $is_admin, + ) + ); + $route_name = "entity.$entity_type_id.entityqueue"; + $collection->add($route_name, $route); + + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events = parent::getSubscribedEvents(); + // Should run after AdminRouteSubscriber so the routes can inherit admin + // status of the edit routes on entities. Therefore priority -210. + $events[RoutingEvents::ALTER] = array('onAlterRoutes', -210); + return $events; + } + +} -- 1.9.1