Bagaimana cara membuat tab pengguna khusus?

9

Saya mencoba membuat tab khusus baru yang muncul di semua rute yang merupakan turunan entitas. {Entity_type} .canonical. Saya telah mencoba memperluas kelas DeriverBase, khususnya mengganti metode getDerivativeDefinitions. Saya membuat tab itu sendiri dengan memperluas LocalTaskDefault dan mengganti metode getRouteParameters. Tab muncul ketika Anda mengunjungi jalur pengguna Drupal standar seperti www.mysite.com/user/1/ atau www.mysite.com/user/1/edit. Namun, ketika kami menambahkan rute pengguna kustom baru kami seperti www.mysite.com/user/1/subscribe, tidak ada tab yang muncul. Apakah ada cara khusus untuk mendefinisikan tugas menu lokal pada rute khusus? Contoh kode:

 $this->derivatives['recurly.subscription_tab'] = [
  'title' => $this->t('Subscription'),
  'weight' => 5,
  'route_name' => 'recurly.subscription_list',
  'base_route' => "entity.$entity_type.canonical",
];

foreach ($this->derivatives as &$entry) {
  $entry += $base_plugin_definition;
}

Terima kasih sebelumnya atas bantuan apa pun.

tflanagan
sumber
Kedengarannya sangat dekat dengan apa yang dilakukan devel dengan itu / devel route / tugas lokal, saya sarankan Anda melihat bagaimana itu mengimplementasikannya.
Berdir
@Berdir itu adalah titik awal tetapi saya sepertinya masih melewatkan sesuatu.
tflanagan
Apakah Anda mencoba menambahkan file 'yourmodule.links.task.yml' dengan pengaturan untuk tab khusus Anda?
Andrew

Jawaban:

7

Seperti yang disarankan oleh Berdir, Anda dapat melihat modul Devel dan bagaimana mengimplementasikannya. Kode berikut "diekstraksi" dari Devel

1) Buat rute

Buat file mymodule.routing.yml di dan di dalam menentukan callback rute (yang digunakan untuk membuat rute dinamis)

route_callbacks:
  - '\Drupal\mymodule\Routing\MyModuleRoutes::routes'

Buat kelas MyModuleRoutes untuk menghasilkan rute dinamis Anda di src / Routing

<?php

namespace Drupal\mymodule\Routing;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

class MyModuleRoutes implements ContainerInjectionInterface {

  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')
    );
  }

  public function routes() {
    $collection = new RouteCollection();

    foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
      if ($entity_type->hasLinkTemplate('canonical')) {
        $route = new Route("/mymodule/$entity_type_id/{{$entity_type_id}}");
        $route
          ->addDefaults([
            '_controller' => '\Drupal\mymodule\Controller\MyModuleController::doStuff',
            '_title' => 'My module route title',
          ])
          ->addRequirements([
            '_permission' => 'access mymodule permission',
          ])
          ->setOption('_mymodule_entity_type_id', $entity_type_id)
          ->setOption('parameters', [
            $entity_type_id => ['type' => 'entity:' . $entity_type_id],
          ]);

        $collection->add("entity.$entity_type_id.mymodule", $route);
      }
    }

    return $collection;
  }

}

2) Buat tugas lokal yang dinamis

Buat file mymodule.links.task.yml dan di dalamnya tentukan deriver

mymodule.tasks:
  class: \Drupal\Core\Menu\LocalTaskDefault
  deriver: \Drupal\mymodule\Plugin\Derivative\MyModuleLocalTasks

Buat kelas MyModuleLocalTasks untuk menghasilkan rute dinamis Anda di src / Plugin / Derivative

<?php

namespace Drupal\mymodule\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyModuleLocalTasks extends DeriverBase implements ContainerDeriverInterface {

  protected $entityTypeManager;

  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  public static function create(ContainerInterface $container, $base_plugin_id) {
    return new static(
      $container->get('entity_type.manager')
    );
  }

  public function getDerivativeDefinitions($base_plugin_definition) {
    $this->derivatives = array();

    foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
      if ($entity_type->hasLinkTemplate('canonical')) {
        $this->derivatives["$entity_type_id.mymodule_tab"] = [
          'route_name' => "entity.$entity_type_id.mymodule",
          'title' => t('Mymodule title'),
          'base_route' => "entity.$entity_type_id.canonical",
          'weight' => 100,
        ] + $base_plugin_definition;
      }
    }

    return $this->derivatives;
  }

}

3) Buat pengontrol

Buat kelas MyModuleController di src / Controller

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;

class MyModuleController extends ControllerBase {

  public function doStuff(RouteMatchInterface $route_match) {
    $output = [];

    $parameter_name = $route_match->getRouteObject()->getOption('_mymodule_entity_type_id');
    $entity = $route_match->getParameter($parameter_name);

    if ($entity && $entity instanceof EntityInterface) {
      $output = ['#markup' => $entity->label()];
    }

    return $output;
  }

}
marco
sumber
3
Ini sangat mirip dengan apa yang akhirnya saya implementasikan. Melewati $ Route_atchatchMeterInterface adalah pemecahan untuk masalah saya. Dari sana objek entitas saya tersedia untuk controller saya.
tflanagan