"Les appels Drupal doivent être évités dans les classes, utilisez plutôt l'injection de dépendances"

17

Dans mon module, utilisez le code ci-dessous pour obtenir l'alias d'URL d'une URL donnée:

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

Mais celui que j'exécute Automated Review ( http://pareview.sh/ ) dans mon module, je reçois ci-dessous l'avertissement:

16 | AVERTISSEMENT | \ Les appels Drupal doivent être évités dans les classes, utilisez plutôt l'injection de dépendances

Comment puis-je mettre à jour le code ci-dessus en utilisant l'injection de dépendance? Mon code de classe entier est donné ci-dessous.

<?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
la source
1
L'autre question ne dit pas expressément comment éviter l'erreur que l'OP affiche ici. Il s'agit plutôt d'une question posée par un utilisateur qui souhaite une confirmation de son plan.
kiamlaluno

Réponses:

16

Prenons l' BlockLibraryControllerexemple de la classe; il étend la même classe que votre contrôleur.

Vous définissez:

  • Une create()méthode statique et publique qui obtient les valeurs du conteneur de dépendances et crée un nouvel objet de votre classe
  • Un constructeur de classe qui enregistre les valeurs passées de la méthode précédente dans les propriétés d'objet
  • Un ensemble de propriétés d'objet pour enregistrer les valeurs passées dans le constructeur de classe

Dans votre cas, le code serait similaire au suivant.

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

}

N'oubliez pas de mettre use \Drupal\Core\Path\AliasManagerInterface;en haut du fichier contenant le code que vous montrez.

En remarque, le code que vous utilisez pour rendre la vue est incorrect: vous n'avez pas besoin de l'utiliser drupal_render()car il views_embed_view()retourne déjà un tableau pouvant être rendu.
Ensuite, le tableau de rendu que vous renvoyez ne donne probablement pas la sortie attendue. #name ne sera probablement pas utilisé depuis Drupal, et #markup filtre le balisage que vous lui passez, comme décrit dans la présentation de l'API Render .

  • #markup : spécifie que le tableau fournit directement le balisage HTML. Sauf si le balisage est très simple, comme une explication dans une balise de paragraphe, il est normalement préférable d'utiliser à la place #theme ou #type, afin que le thème puisse personnaliser le balisage. Notez que la valeur est transmise \Drupal\Component\Utility\Xss::filterAdmin(), ce qui supprime les vecteurs XSS connus tout en autorisant une liste permissive de balises HTML qui ne sont pas des vecteurs XSS. (C'est-à-dire, <script>et <style>ne sont pas autorisés.) Voir \Drupal\Component\Utility\Xss::$adminTagspour la liste des balises qui seront autorisées. Si votre balisage nécessite des balises qui ne figurent pas dans cette liste blanche, vous pouvez implémenter un hook de thème et un fichier de modèle et / ou une bibliothèque de ressources. Vous pouvez également utiliser la clé de tableau de rendu #allowed_tags pour modifier les balises filtrées.

  • #allowed_tags : si #markup est fourni, cela peut être utilisé pour changer les balises utilisées pour filtrer le balisage. La valeur doit être un tableau de balises Xss::filter()acceptant. Si #plain_text est défini, cette valeur est ignorée.

kiamlaluno
la source
1
Cela m'aide beaucoup. L'injection de dépendances fonctionne bien. :) Merci.
ARUN
views_embed_view () ne fournissant qu'un tableau. Sans utiliser drupal_render (), comment puis-je l'afficher en tant que contenu html?
ARUN
Il renvoie un tableau pouvant être rendu, qui peut être renvoyé à partir de la méthode du contrôleur qui rend une page.
kiamlaluno
Il suffit de retourner ce qui views_embed_view()revient.
kiamlaluno
mon contrôleur utilise pour un appel ajax. le contenu renvoyé sera mis à jour de manière dynamique dans la page. En retournant le résultat de views_embed_view()celui - ci montrantArray
ARUN
1

Afin d'utiliser l'injection de dépendances, votre classe doit implémenter une ContainerInjectionInterfaceinterface. ContainerInjectionInterfaceexige que la classe d'implémentation ait une create()méthode. Avec un constructeur de classe supplémentaire qui accepte les dépendances injectées, la create()méthode retourne une instance de votre classe en passant les instances définies de dépendances à votre classe.

Mise à jour: Il a été souligné à juste titre par @kiamlaluno qui ContainerInjectionInterfacen'est pas requis dans ce cas car ControllerBaseil l'implémente déjà.

<?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
la source
Il suffit de vous étendre ControllerBase; il n'est pas nécessaire de l'implémenter ContainerInjectionInterfacepuisque cela se fait déjà depuis ControllerBase.
kiamlaluno
@kiamlaluno, c'est exact. votre code fonctionne parfaitement.
ARUN