Bagaimana cara mengubah rute yang ditentukan oleh modul lain?


14

Dengan kata lain, apa yang setara dengan Drupl 8 dari hook_menu_alter () ?

Drupal 8 masih menggunakan hook_menu () , tetapi untuk apa yang dapat saya lihat, informasi yang dikembalikan oleh hook berbeda dengan apa yang dikembalikan oleh hook pada Drupal 7. Sebagai contoh, definisi yang diberikan dalam user_menu () untuk pengguna adalah sebagai berikut.

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

Properti route_name menautkan ke entri dalam file user.routing.yml .

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

Ini berbeda dari apa yang dilakukan dengan Symphony, dan itu membingungkan saya tentang bagaimana sebuah modul dapat mengubah rute yang ditentukan dari pengguna lain.

Satu-satunya fungsi yang masih menjalankan hook_menu_alter()adalah menu_router_build () , tetapi fungsi itu masih berisi kode yang perlu diperbarui, karena masih menggunakan yang sekarang sudah tidak digunakan lagi 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;
    }
  }

Jawaban:


6

Lihat Mengubah rute yang ada dan menambahkan rute baru berdasarkan yang dinamis ; itu bekerja dengan baik bagi saya untuk menghapus / mencari yang ditangani oleh modul Pencarian. Dalam kasus saya, saya menggunakan kode berikut.

<?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');
  }

}

12

Izinkan tampilan untuk mengganti item perutean yang ada hanya menggunakan fungsionalitas yang ada.

Jika Anda ingin mengubah informasi yang dilampirkan pada rute, bukan menu, seperti controller yang sebenarnya digunakan, atau persyaratan (izin / peran dll.) Anda dapat menggunakan acara yang disediakan oleh Drupal:

  <?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');
    }
  }

  }

Selain itu Anda harus mendaftarkan layanan dengan tag 'event_subscriber' untuk kelas ini.


Ada detail untuk menyiapkan pendaftaran layanan di Mengubah rute yang ada dan menambahkan rute baru berdasarkan yang dinamis .
colan

7

Sejak saya mengajukan pertanyaan ini, inti Drupal 8 berubah, dan beberapa masalah tentang rute telah diperbaiki.

hook_menu()tidak digunakan dari Drupal 8 lagi; rute yang digunakan modul didefinisikan dalam file .routing.yml (mis. user.routing.yml ). Alter hooks masih digunakan, tetapi karena hook_menu()tidak digunakan lagi dari inti Drupal, hook_menu_alter()tidak digunakan.

Langkah-langkah yang diperlukan untuk mengubah rute yang ditentukan dari modul lain adalah sebagai berikut:

  • Tentukan layanan

    services:
      mymodule.route_subscriber:
        class: Drupal\mymodule\Routing\RouteSubscriber
        tags:
          - { name: event_subscriber }
  • Buat kelas yang memperluas RouteSubscriberBasekelas.

    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');
        }
      }
    
    }

Perhatikan bahwa dibandingkan dengan rilis Drupal 8 sebelumnya, beberapa detail diubah.

  • Nama rute diubah dari user_pagemenjadiuser.page
  • Persyaratan untuk rute itu berubah dari _access: 'TRUE'menjadi_user_is_logged_in: 'TRUE'
  • Properti untuk mengatur pengontrol rute berubah dari _contentmenjadi_controller

Jika Anda ingin mencocokkan beberapa rute, apakah ada cara yang lebih elegan daripada menetapkan variabel $ cocok ke false, lalu mengulanginya semua satu per satu dengan $collection->get()? Saya tidak bisa melihat metode yang jelas.
William Turrell

@ WillillTurrell Anda bisa mendapatkan ArrayIteratorobjek dengan RouteCollection::getIterator(); yang akan membuat lebih mudah untuk beralih ke semua item di $collection. Anda juga bisa mendapatkan semua rute $collectiondengan RouteCollection::all(), yang mengembalikan array.
kiamlaluno
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.