«В классах следует избегать вызовов Drupal, вместо этого используйте внедрение зависимостей»

17

В моем модуле используется код ниже для получения псевдонима URL данного URL:

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

Но в моем модуле я запускаю Automated Review ( http://pareview.sh/ ), ниже которого выдается предупреждение:

16 | ВНИМАНИЕ | В классах следует избегать вызовов Drupal, вместо этого используйте внедрение зависимостей

Как я могу обновить приведенный выше код с помощью внедрения зависимостей? Весь мой код класса приведен ниже.

<?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
источник
1
Другой вопрос прямо не говорит о том, как избежать ошибки, которую показывает здесь OP. Это скорее вопрос от пользователя, который хочет подтвердить свой план.
kiamlaluno

Ответы:

16

Возьмите BlockLibraryControllerкласс в качестве примера; он расширяет тот же класс, что и ваш контроллер.

Вы определяете:

  • Статический и публичный create()метод, который получает значения из контейнера зависимостей и создает новый объект вашего класса.
  • Конструктор класса , который сохраняет значения , передаваемые от предыдущего метода в свойствах объекта
  • Набор свойств объекта для сохранения значений, переданных в конструкторе класса

В вашем случае код будет похож на следующий.

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

}

Не забудьте поместить use \Drupal\Core\Path\AliasManagerInterface;в начало файла, содержащего код, который вы показываете.

Как примечание: код, который вы используете для визуализации представления, неверен: вам не нужно его использовать, drupal_render()потому что он views_embed_view()уже возвращает рендеринг-массив.
Тогда возвращаемый массив рендеринга, вероятно, не дает ожидаемого результата. #name, вероятно, не будет использоваться из Drupal, и #markup фильтрует разметку, которую вы ему передаете, как описано в обзоре Render API .

  • #markup : указывает, что массив предоставляет разметку HTML напрямую. Если разметка не является очень простой, такой как пояснение в теге абзаца, обычно предпочтительно вместо этого использовать #theme или #type, чтобы тема могла настраивать разметку. Обратите внимание, что передается значение \Drupal\Component\Utility\Xss::filterAdmin(), которое удаляет известные векторы XSS, в то же время разрешая разрешающий список тегов HTML, которые не являются векторами XSS. (То есть <script>и <style>не разрешены.) См. \Drupal\Component\Utility\Xss::$adminTagsСписок тегов, которые будут разрешены. Если вашей разметке нужны какие-либо теги, которых нет в этом белом списке, вы можете реализовать хук темы и файл шаблона и / или библиотеку ресурсов. Кроме того, вы можете использовать ключ массива рендеринга #allowed_tags, чтобы изменить, какие теги фильтруются.

  • #allowed_tags : Если указан #markup, это можно использовать для изменения тегов, используемых для фильтрации разметки. Значение должно быть массивом тегов, которые Xss::filter()будут принимать. Если #plain_text установлен, это значение игнорируется.

киамалуно
источник
1
Это мне очень помогает. Зависимость инъекций работает нормально. :) Спасибо.
Арун
views_embed_view () предоставляет только массив. Без использования drupal_render (), как я могу отобразить его как HTML-контент?
Арун
Он возвращает визуализируемый массив, который можно вернуть из метода контроллера, который отображает страницу.
kiamlaluno
Просто верни то, что views_embed_view()вернул.
kiamlaluno
мой контроллер использует для вызова ajax. возвращаемый контент будет обновляться на странице динамически. Пока возвращаю результат views_embed_view()этого показаArray
ARUN
1

Чтобы использовать внедрение зависимостей, ваш класс должен реализовать ContainerInjectionInterfaceинтерфейс. ContainerInjectionInterfaceтребует, чтобы у реализующего класса был create()метод. С дополнительным конструктором класса, который принимает введенные зависимости, create()метод возвращает экземпляр вашего класса, передавая определенные экземпляры зависимостей вашему классу.

Обновление: @kiamlaluno по праву указал, что ContainerInjectionInterfaceв этом случае не требуется, поскольку он ControllerBaseуже реализован.

<?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
источник
Достаточно, чтобы вы продлили ControllerBase; это не нужно реализовывать, ContainerInjectionInterfaceпоскольку это уже сделано из ControllerBase.
kiamlaluno
@kiamlaluno, это правильно. ваш код работает отлично.
Арун