„W klasach należy unikać wywołań Drupala, zamiast tego należy stosować wstrzykiwanie zależności”

16

W moim module używam poniższego kodu do uzyskania aliasu adresu URL danego adresu:

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

Ale w moim module uruchamiam automatyczną recenzję ( http://pareview.sh/ ). Pojawia się poniżej ostrzeżenie:

16 | OSTRZEŻENIE | \ Wywołania Drupala należy unikać w klasach, zamiast tego należy stosować wstrzykiwanie zależności

Jak mogę zaktualizować powyższy kod za pomocą wstrzykiwania zależności? Cały mój kod klasy podano poniżej.

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

}
BIEG
źródło
1
Drugie pytanie nie mówi wprost, jak uniknąć błędu, który pokazuje tutaj OP. Jest to raczej pytanie zadane przez użytkownika, który chce potwierdzić swój plan.
kiamlaluno

Odpowiedzi:

16

Weź BlockLibraryControllerklasę jako przykład; rozszerza tę samą klasę, co twój kontroler.

Ty definiujesz:

  • create()Metoda statyczna i publiczna , która pobiera wartości z kontenera zależności i tworzy nowy obiekt twojej klasy
  • Konstruktor klas, który zapisuje wartości przekazane z poprzedniej metody we właściwościach obiektu
  • Zestaw właściwości obiektu do zapisywania wartości przekazanych w konstruktorze klas

W twoim przypadku kod byłby podobny do następującego.

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.
  }

}

Nie zapomnij umieścić use \Drupal\Core\Path\AliasManagerInterface;na wierzchu pliku zawierającego wyświetlany kod.

Na marginesie, kod użyty do renderowania widoku jest niepoprawny: Nie musisz go używać, drupal_render()ponieważ views_embed_view()już zwraca tablicę do renderowania.
Następnie zwracana tablica renderowania prawdopodobnie nie zapewnia oczekiwanego wyniku. #nazwa prawdopodobnie nie będzie używana z Drupala, a #markup filtruje przekazane do niego znaczniki, jak opisano w przeglądzie API renderingu .

  • #markup : Określa, że ​​tablica zapewnia bezpośrednio znaczniki HTML. O ile znaczniki nie są bardzo proste, takie jak objaśnienie znaczników akapitu, zwykle lepiej jest użyć #theme lub #type, aby motyw mógł dostosować znaczniki. Zauważ, że wartość jest przekazywana \Drupal\Component\Utility\Xss::filterAdmin(), która usuwa znane wektory XSS, jednocześnie dopuszczając listę dozwolonych znaczników HTML, które nie są wektorami XSS. (Tj. <script>I <style>nie są dozwolone.) Sprawdź \Drupal\Component\Utility\Xss::$adminTagslistę tagów, które będą dozwolone. Jeśli znaczniki wymagają któregokolwiek ze znaczników, których nie ma na białej liście, możesz zaimplementować hak motywu i plik szablonu i / lub bibliotekę zasobów. Alternatywnie możesz użyć klucza tablicy renderowania #allowed_tags, aby zmienić, które tagi są filtrowane.

  • #allowed_tags : Jeśli podano #markup, można go użyć do zmiany, które tagi używają do filtrowania znaczników. Wartością powinna być tablica tagów, które Xss::filter()by zaakceptowały. Jeśli ustawiony jest #plain_text, ta wartość jest ignorowana.

kiamlaluno
źródło
1
To mi bardzo pomaga. Wstrzyknięcie zależności działa dobrze. :) Dziękuję Ci.
ARUN
views_embed_view () tylko zapewnia tablicę. Bez używania drupal_render () jak mogę wyświetlić go jako treść HTML?
ARUN
Zwraca tablicę do renderowania, którą można zwrócić z metody kontrolera renderującej stronę.
kiamlaluno
Zwróć tylko to, co views_embed_view()powróci.
kiamlaluno
mój kontroler używa do wywołania ajax. zwrócona treść będzie aktualizowana na stronie dynamicznie. Podczas gdy zwraca wynik views_embed_view()pokazującyArray
ARUN
1

Aby wykorzystać wstrzykiwanie zależności, klasa musi implementować ContainerInjectionInterfaceinterfejs.ContainerInjectionInterfacenakazuje, że klasa implementująca musi mieć create()metodę. Dzięki dodatkowemu konstruktorowi klasy, który akceptuje wstrzykiwane zależności, create()metoda zwraca instancję klasy, przekazując zdefiniowane instancje zależności do klasy.

Aktualizacja: słusznie wskazał @kiamlaluno, który ContainerInjectionInterfacenie jest wymagany w tym przypadku, ponieważ ControllerBasejuż go implementuje.

<?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
źródło
Wystarczy rozszerzyć ControllerBase; wdrożenie nie jest konieczne, ContainerInjectionInterfaceponieważ zostało to już zrobione ControllerBase.
kiamlaluno
@kiamlaluno, to prawda. Twój kod działa idealnie.
ARUN