Wie ändere ich die von einem anderen Modul definierte Route?

14

Mit anderen Worten, was ist das Drupl 8-Äquivalent von hook_menu_alter () ?

Drupal 8 verwendet immer noch hook_menu () , aber soweit ich sehen kann, unterscheiden sich die vom Hook zurückgegebenen Informationen von denen, die der Hook in Drupal 7 zurückgegeben hat. Die Definition in user_menu () für user lautet beispielsweise wie folgt.

  $items['user'] = array(
    'title' => 'User account',
    'title callback' => 'user_menu_title',
    'weight' => -10,
    'route_name' => 'user_page',
    'menu_name' => 'account',
  );

Die Eigenschaft route_name verweist auf einen Eintrag in der Datei user.routing.yml .

user_page:
  pattern: '/user'
  defaults:
    _content: '\Drupal\user\Controller\UserController::userPage'
  requirements:
    _access: 'TRUE'

Dies unterscheidet sich von der Vorgehensweise in Symphony, und es verwirrt mich, wie ein Modul die von einem anderen Benutzer definierte Route ändern kann.

Die einzige Funktion, die immer noch aufgerufen wird, hook_menu_alter()ist menu_router_build () , aber diese Funktion enthält immer noch Code, der aktualisiert werden muss, da sie immer noch den jetzt veralteten Code verwendet drupal_alter().

  // Alter the menu as defined in modules, keys are like user/%user.
  drupal_alter('menu', $callbacks);
  foreach ($callbacks as $path => $router_item) {
    // If the menu item is a default local task and incorrectly references a
    // route, remove it.
    // @todo This may be removed later depending on the outcome of
    // http://drupal.org/node/1889790
    if (isset($router_item['type']) && $router_item['type'] == MENU_DEFAULT_LOCAL_TASK) {
      unset($callbacks[$path]['route_name']);
    }
    // If the menu item references a route, normalize the route information
    // into the old structure. Note that routes are keyed by name, not path,
    // so the path of the route takes precedence.
    if (isset($router_item['route_name'])) {
      $router_item['page callback'] = 'USES_ROUTE';
      $router_item['access callback'] = TRUE;
      $new_path = _menu_router_translate_route($router_item['route_name']);

      unset($callbacks[$path]);
      $callbacks[$new_path] = $router_item;
    }
  }
kiamlaluno
quelle

Antworten:

6

Siehe Ändern vorhandener Routen und Hinzufügen neuer Routen basierend auf dynamischen Routen . Es funktionierte gut für mich, die vom Suchmodul bearbeitete Suche zu entfernen. In meinem Fall habe ich den folgenden Code verwendet.

<?php
/**
 * @file
 * Contains \Drupal\ua_sc_module\Routing\SearchAlterRouteSubscriber.
 */

namespace Drupal\ua_sc_module\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class SearchAlterRouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {
    // Remove the /search route.
    $collection->remove('search.view');
  }

}
tzm
quelle
12

Wenn Sie zulassen, dass Ansichten vorhandene Routingelemente überschreiben, werden nur die vorhandenen Funktionen verwendet.

Wenn Sie die an eine Route angehängten Informationen ändern möchten, nicht das Menü, wie den tatsächlich verwendeten Controller oder die Anforderungen (Berechtigung / Rolle usw.), können Sie ein von Drupal bereitgestelltes Ereignis verwenden:

  <?php

  use Drupal\Core\Routing\RouteBuildEvent;
  use Drupal\Core\Routing\RoutingEvents;
  use Symfony\Component\EventDispatcher\EventSubscriberInterface;

  class RouteSubscriber implements EventSubscriberInterface {

   /**
    * {@inheritdoc}
    */
   public static function getSubscribedEvents() {
      $events[RoutingEvents::ALTER] = 'alterRoutes';
     return $events;
   }

  /**
   * Alters existing routes.
   *
   * @param \Drupal\Core\Routing\RouteBuildEvent $event
   *   The route building event.
   */
  public function alterRoutes(RouteBuildEvent $event) {
    // Fetch the collection which can be altered.
    $collection = $event->getRouteCollection();
    // The event is fired multiple times so ensure that the user_page route
    // is available.
    if ($route = $collection->get('user_page')) {
      // As example add a new requirement.
      $route->setRequirement('_role', 'anonymous');
    }
  }

  }

Zusätzlich müssen Sie einen Service mit dem Tag 'event_subscriber' für diese Klasse registrieren.

Daniel Wehner
quelle
Details zum Einrichten der Dienstregistrierung finden Sie unter Ändern vorhandener Routen und Hinzufügen neuer Routen basierend auf dynamischen Routen .
Colan
7

Seitdem ich diese Frage gestellt habe, hat sich der Drupal 8-Kern geändert und einige Probleme mit Routen wurden behoben.

hook_menu()wird ab Drupal 8 nicht mehr verwendet; Die von einem Modul verwendeten Routen werden in einer .routing.yml-Datei definiert (z . B. user.routing.yml ). Alter Hooks werden immer noch verwendet, aber da er hook_menu()nicht mehr vom Drupal-Kern verwendet wird, hook_menu_alter()wird er auch nicht verwendet.

Folgende Schritte sind erforderlich, um eine in anderen Modulen definierte Route zu ändern:

  • Definieren Sie einen Service

    services:
      mymodule.route_subscriber:
        class: Drupal\mymodule\Routing\RouteSubscriber
        tags:
          - { name: event_subscriber }
  • Erstellen Sie eine Klasse, die die RouteSubscriberBaseKlasse erweitert.

    namespace Drupal\mymodule\Routing;
    
    use Drupal\Core\Routing\RouteSubscriberBase;
    use Symfony\Component\Routing\RouteCollection;
    
    /**
     * Listens to the dynamic route events.
     */
    class RouteSubscriber extends RouteSubscriberBase {
    
      /**
       * {@inheritdoc}
       */
      protected function alterRoutes(RouteCollection $collection) {
        // Change the route associated with the user profile page (/user, /user/{uid}).
        if ($route = $collection->get('user.page')) {
          $route->setDefault('_controller', '\Drupal\mymodule\Controller\UserController::userPage');
        }
      }
    
    }

Beachten Sie, dass im Vergleich zu früheren Drupal 8-Versionen einige Details geändert wurden.

  • Der Routenname wird von user_pagenach geändertuser.page
  • Die Anforderungen für diese Route haben sich von _access: 'TRUE'nach geändert_user_is_logged_in: 'TRUE'
  • Die Eigenschaft zum Festlegen des Controllers einer Route wurde von _contentnach geändert_controller
kiamlaluno
quelle
Wenn Sie mehrere Routen abgleichen möchten, gibt es eine elegantere Möglichkeit, als eine $ matched-Variable auf false zu setzen und dann alle nacheinander mit $collection->get()durchzugehen. Ich kann keine offensichtlichen Methoden sehen.
William Turrell
@ WilliamTurrell Sie können ein ArrayIteratorObjekt mit RouteCollection::getIterator(); Das würde es einfacher machen, alle Elemente in zu durchlaufen $collection. Sie können auch alle Routen $collectionmit RouteCollection::all()einlesen, wodurch ein Array zurückgegeben wird.
kiamlaluno