"Drupal-Aufrufe sollten in Klassen vermieden werden. Verwenden Sie stattdessen Dependency Injection."

16

In meinem Modul verwende ich den folgenden Code, um den URL-Alias ​​der angegebenen URL zu erhalten:

$alias = \Drupal::service('path.alias_manager')->getPathByAlias($_POST['url']);

Bei einem Modul, für das ich Automated Review ( http://pareview.sh/ ) ausführe , wird die folgende Warnung angezeigt:

16 | WARNUNG | \ Drupal-Aufrufe sollten in Klassen vermieden werden. Verwenden Sie stattdessen die Abhängigkeitsinjektion

Wie kann ich den obigen Code mithilfe der Abhängigkeitsinjektion aktualisieren? Mein gesamter Klassencode ist unten angegeben.

<?php

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;

/**
 * MyModule Class defines ajax callback function.
 */
class MyModule extends ControllerBase {
/**
 * Callback function for ajax request.
 */

  public function getUserContent() {
    $alias = \Drupal::service('path.alias_manager')->getPathByAlias($_POST['url']);
    $alias = explode('/', $alias);
    $my_module_views = views_embed_view('my_module', 'default', $alias[2]);
    $my_module= drupal_render($my_module_views);
    return array(
      '#name' => 'my_module_content',
      '#markup' => '<div class="my_module_content">' . $my_module. '</div>',
    );
  }

}
ARUN
quelle
1
Die andere Frage besagt nicht ausdrücklich, wie der Fehler vermieden werden kann, den das OP hier anzeigt. Es ist eher eine Frage, die von einem Benutzer gestellt wird, der eine Bestätigung seines Plans wünscht.
Kiamlaluno

Antworten:

16

Nehmen Sie die BlockLibraryControllerKlasse als Beispiel. Es erweitert die gleiche Klasse wie Ihr Controller.

Sie definieren:

  • Eine statische und öffentliche create()Methode, die die Werte aus dem Abhängigkeitscontainer abruft und ein neues Objekt Ihrer Klasse erstellt
  • Ein Klassenkonstruktor , der die von der vorherigen Methode übergebenen Werte in den Objekteigenschaften speichert
  • Eine Reihe von Objekteigenschaften zum Speichern der im Klassenkonstruktor übergebenen Werte

In Ihrem Fall ähnelt der Code dem folgenden.

class MyModuleController extends ControllerBase {
  /**
   * The path alias manager.
   *
   * @var \Drupal\Core\Path\AliasManagerInterface
   */
  protected aliasManager;

  /**
   * Constructs a MyModuleController object.
   *
   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
   *   The path alias manager.
   */
  public function __construct(AliasManagerInterface $alias_manager) {
    $this->aliasManager = $alias_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('path.alias_manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getUserContent() {
    $alias = $this->aliasManager->getPathByAlias($_POST['url']);
    // Omissis.
  }

}

Vergessen Sie nicht, use \Drupal\Core\Path\AliasManagerInterface;den Kopf der Datei mit dem angezeigten Code zu setzen.

Als Randnotiz ist der Code, den Sie zum Rendern der Ansicht verwenden, falsch: Sie müssen ihn nicht verwenden, drupal_render()da views_embed_view()bereits ein wiedergebbares Array zurückgegeben wird.
Dann liefert das zurückgegebene Render-Array wahrscheinlich nicht die erwartete Ausgabe. #name wird in Drupal wahrscheinlich nicht verwendet, und #markup filtert das Markup, das Sie an ihn übergeben, wie in der Render-API-Übersicht beschrieben .

  • #markup : Gibt an, dass das Array HTML-Markup direkt bereitstellt. Sofern das Markup nicht sehr einfach ist, z. B. eine Erklärung in einem Absatz-Tag, ist es normalerweise vorzuziehen, stattdessen #theme oder #type zu verwenden, damit das Design das Markup anpassen kann. Beachten Sie, dass der Wert durchgereicht wird \Drupal\Component\Utility\Xss::filterAdmin(), wodurch bekannte XSS-Vektoren entfernt werden, während eine zulässige Liste von HTML-Tags angezeigt wird, die keine XSS-Vektoren sind. (Das heißt, <script>und <style>sind nicht zulässig.) Eine \Drupal\Component\Utility\Xss::$adminTagsListe der zulässigen Tags finden Sie unter. Wenn für Ihr Markup Tags erforderlich sind, die nicht in dieser Whitelist enthalten sind, können Sie einen Design-Hook und eine Vorlagendatei und / oder eine Asset-Bibliothek implementieren. Alternativ können Sie den Render-Array-Schlüssel #allowed_tags verwenden, um zu ändern, welche Tags gefiltert werden.

  • #allowed_tags : Wenn #markup angegeben ist, kann hiermit geändert werden, welche Tags zum Filtern des Markups verwendet werden. Der Wert sollte ein Array von Tags sein, Xss::filter()die akzeptiert würden. Wenn #plain_text gesetzt ist, wird dieser Wert ignoriert.

kiamlaluno
quelle
1
Das hilft mir sehr. Abhängigkeitsinjektion funktioniert gut. :) Vielen Dank.
ARUN
views_embed_view () liefert nur ein Array. Wie kann ich es ohne Verwendung von drupal_render () als HTML-Inhalt anzeigen?
ARUN
Es gibt ein darstellbares Array zurück, das von der Controller-Methode zurückgegeben werden kann, die eine Seite darstellt.
Kiamlaluno
Einfach zurückgeben, was views_embed_view()zurückkommt.
kiamlaluno
Mein Controller verwendet für einen Ajax-Anruf. Der zurückgegebene Inhalt wird auf der Seite dynamisch aktualisiert. Während Rückkehr das Ergebnis views_embed_view()es zeigtArray
ARUN
1

Um die Abhängigkeitsinjektion zu verwenden, muss Ihre Klasse eine ContainerInjectionInterfaceSchnittstelle implementieren . ContainerInjectionInterfacegibt vor, dass die implementierende Klasse eine create()Methode haben muss. Mit einem zusätzlichen Klassenkonstruktor, der die injizierten Abhängigkeiten akzeptiert, gibt die create()Methode eine Instanz Ihrer Klasse zurück, indem die definierten Instanzen von Abhängigkeiten an Ihre Klasse übergeben werden.

Update: Es wurde von @kiamlaluno zu Recht darauf hingewiesen, dass ContainerInjectionInterfacedies in diesem Fall nicht erforderlich ist, da es ControllerBasebereits implementiert ist.

<?php

namespace Drupal\my_module\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Path\AliasManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * MyModule Class defines ajax callback function.
 */
class MyModule extends ControllerBase {

  /** @var \Drupal\Core\Path\AliasManagerInterface $aliasManager */
  protected $aliasManager;

  /**
   * MyModule constructor.
   *
   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
   */
  public function __construct(AliasManagerInterface $alias_manager) {
    $this->aliasManager = $alias_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('path.alias_manager')
    );
  }

  /**
   * Callback function for ajax request.
   */
  public function getUserContent() {
    $alias = $this->aliasManager->getPathByAlias($_POST['url']);
    // Your code.
  }

}
maijs
quelle
Es ist genug, dass Sie verlängern ControllerBase; Eine Implementierung ist nicht erforderlich, ContainerInjectionInterfaceda dies bereits ab erfolgt ist ControllerBase.
kiamlaluno
@kiamlaluno, das ist richtig. Ihr Code funktioniert perfekt.
ARUN