"Las llamadas de Drupal deben evitarse en las clases, en su lugar use la inyección de dependencia"

17

En mi módulo, uso el siguiente código para obtener el alias de la URL dada:

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

Pero una vez que ejecuto la Revisión automatizada ( http://pareview.sh/ ) en mi módulo, recibo la siguiente advertencia:

16 ADVERTENCIA | \ Las llamadas de Drupal deben evitarse en las clases, utilice la inyección de dependencia

¿Cómo puedo actualizar el código anterior usando la inyección de dependencia? Mi código de clase completo se da a continuación.

<?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
fuente
1
La otra pregunta no dice expresamente cómo evitar el error que muestra el OP aquí. Es más bien una pregunta hecha por un usuario que quiere una confirmación sobre su plan.
kiamlaluno

Respuestas:

16

Toma la BlockLibraryControllerclase como ejemplo; extiende la misma clase que su controlador.

Usted define:

  • Un create()método público y estático que obtiene los valores del contenedor de dependencias y crea un nuevo objeto de su clase.
  • Un constructor de clase que guarda los valores pasados ​​del método anterior en las propiedades del objeto.
  • Un conjunto de propiedades de objeto para guardar los valores pasados ​​en el constructor de la clase.

En su caso, el código sería similar al siguiente.

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

}

No olvide poner use \Drupal\Core\Path\AliasManagerInterface;en la parte superior del archivo que contiene el código que está mostrando.

Como nota al margen, el código que usa para representar la vista es incorrecto: no necesita usarlo drupal_render()porque views_embed_view()ya devuelve una matriz renderizable.
Entonces, la matriz de renderizado que está devolviendo probablemente no esté dando el resultado que espera. #name probablemente no se utilizará desde Drupal, y #markup filtra el marcado que le está pasando, como se describe en la descripción general de la API Render .

  • #markup : especifica que la matriz proporciona marcado HTML directamente. A menos que el marcado sea muy simple, como una explicación en una etiqueta de párrafo, normalmente es preferible usar #theme o #type, para que el tema pueda personalizar el marcado. Tenga en cuenta que el valor se pasa \Drupal\Component\Utility\Xss::filterAdmin(), lo que elimina los vectores XSS conocidos mientras permite una lista permisiva de etiquetas HTML que no son vectores XSS. (Es decir, <script>y <style>no están permitidos). Consulte \Drupal\Component\Utility\Xss::$adminTagsla lista de etiquetas que se permitirán. Si su marcado necesita alguna de las etiquetas que no están en esta lista blanca, puede implementar un enlace de tema y un archivo de plantilla y / o una biblioteca de activos. Alternativamente, puede usar la clave de matriz de representación #allowed_tags para modificar las etiquetas que se filtran.

  • #allowed_tags : si se proporciona #markup, esto se puede usar para cambiar las etiquetas que se usan para filtrar el marcado. El valor debe ser una matriz de etiquetas que Xss::filter()acepte. Si se establece #plain_text, este valor se ignora.

kiamlaluno
fuente
1
Esto me ayuda mucho. La inyección de dependencia funciona bien. :) Gracias.
ARUN
views_embed_view () solo proporciona una matriz. Sin usar drupal_render (), ¿cómo puedo mostrarlo como contenido html?
ARUN
Devuelve una matriz renderizable, que puede devolverse desde el método del controlador que representa una página.
kiamlaluno
Solo devuelve lo que views_embed_view()vuelve.
kiamlaluno
mi controlador está usando para una llamada ajax. El contenido devuelto se actualizará en la página dinámicamente. Mientras devuelve el resultado de views_embed_view()su presentaciónArray
ARUN
1

Para utilizar la inyección de dependencia, su clase necesita implementar una ContainerInjectionInterfaceinterfaz. ContainerInjectionInterfacemandatos que implementando la clase tiene que tener create()método. Con un constructor de clase adicional que acepta las dependencias inyectadas, el create()método devuelve una instancia de su clase al pasar las instancias definidas de dependencias a su clase.

Actualización: @kiamlaluno señaló acertadamente que ContainerInjectionInterfaceno es necesario en este caso ya que ControllerBaseya lo implementa.

<?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
fuente
Es suficiente que extiendas ControllerBase; no es necesario implementar ContainerInjectionInterfaceya que eso ya se hizo desde ControllerBase.
kiamlaluno
@kiamlaluno, eso es correcto. Tu código funciona perfecto.
ARUN