“Panggilan Drupal harus dihindari di kelas, gunakan injeksi ketergantungan sebagai gantinya”

17

Dalam modul saya menggunakan kode di bawah ini untuk mendapatkan url alias dari url yang diberikan:

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

Tapi yang saya jalankan Ulasan Otomatis ( http://pareview.sh/ ) dalam modul saya, saya mendapatkan peringatan di bawah ini:

16 | PERINGATAN | \ Panggilan Drupal harus dihindari di kelas, gunakan injeksi ketergantungan sebagai gantinya

Bagaimana saya bisa memperbarui kode di atas menggunakan injeksi ketergantungan? Seluruh kode kelas saya diberikan di bawah ini.

<?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
sumber
1
Pertanyaan lain tidak secara tegas mengatakan bagaimana cara menghindari kesalahan yang ditunjukkan OP di sini. Ini lebih merupakan pertanyaan yang dibuat dari pengguna yang menginginkan konfirmasi tentang rencananya.
kiamlaluno

Jawaban:

16

Ambil BlockLibraryControllerkelas sebagai contoh; itu memperluas kelas yang sama dengan controller Anda.

Anda mendefinisikan:

  • Metode statis dan publik create()yang mendapatkan nilai dari wadah dependensi, dan membuat objek baru kelas Anda
  • Sebuah konstruktor kelas yang menyimpan nilai-nilai lulus dari metode sebelumnya di properti obyek
  • Seperangkat properti objek untuk menyimpan nilai yang diteruskan dalam konstruktor kelas

Dalam kasus Anda, kode akan serupa dengan yang berikut.

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

}

Jangan lupa letakkan use \Drupal\Core\Path\AliasManagerInterface;di bagian atas file yang berisi kode yang Anda tampilkan .

Sebagai catatan tambahan, kode yang Anda gunakan untuk membuat tampilan salah: Anda tidak perlu menggunakan drupal_render()karena views_embed_view()sudah mengembalikan array yang dapat diulang.
Kemudian, array render yang Anda kembalikan mungkin tidak memberikan output yang Anda harapkan. #name mungkin tidak akan digunakan dari Drupal, dan #markup menyaring markup yang Anda lewati, seperti yang dijelaskan pada ikhtisar Render API .

  • #markup : Menentukan bahwa array menyediakan markup HTML secara langsung. Kecuali jika markupnya sangat sederhana, seperti penjelasan dalam tag paragraf, biasanya lebih baik menggunakan #theme atau #type sebagai gantinya, sehingga tema dapat menyesuaikan markup. Perhatikan bahwa nilainya diteruskan \Drupal\Component\Utility\Xss::filterAdmin(), yang menghapus vektor XSS yang diketahui sambil memungkinkan daftar tag HTML yang permisif yang bukan vektor XSS. (Yaitu, <script>dan <style>tidak diizinkan.) Lihat \Drupal\Component\Utility\Xss::$adminTagsdaftar tag yang akan diizinkan. Jika markup Anda membutuhkan salah satu tag yang tidak ada dalam daftar putih ini, maka Anda dapat menerapkan kait tema dan file templat dan / atau pustaka aset. Atau, Anda dapat menggunakan kunci array render #allowed_tags untuk mengubah tag mana yang difilter.

  • #allowed_tags : Jika #markup disediakan ini dapat digunakan untuk mengubah tag mana yang digunakan untuk memfilter markup. Nilai harus berupa array tag yang Xss::filter()akan menerima. Jika #plain_text disetel, nilai ini diabaikan.

kiamlaluno
sumber
1
Ini sangat membantu saya. Ketergantungan injeksi bekerja dengan baik. :) Terima kasih.
ARUN
views_embed_view () hanya menyediakan array. Tanpa menggunakan drupal_render () bagaimana saya bisa menampilkannya sebagai konten html?
ARUN
Ini mengembalikan array yang dapat diulang, yang dapat dikembalikan dari metode pengontrol yang membuat halaman.
kiamlaluno
Kembalikan apa yang views_embed_view()dikembalikan.
kiamlaluno
controller saya gunakan untuk panggilan ajax. konten yang dikembalikan akan diperbarui di halaman secara dinamis. Sambil mengembalikan hasil views_embed_view()yang ditampilkanArray
ARUN
1

Untuk menggunakan injeksi dependensi, kelas Anda perlu mengimplementasikan ContainerInjectionInterfaceantarmuka. ContainerInjectionInterfacemengamanatkan bahwa kelas implementasi harus memiliki create()metode. Dengan konstruktor kelas tambahan yang menerima dependensi yang disuntikkan, create()metode mengembalikan instance kelas Anda dengan meneruskan turunan dependensi yang ditentukan ke kelas Anda.

Pembaruan: Seharusnya ditunjuk oleh @kiamlaluno yang ContainerInjectionInterfacetidak diperlukan dalam kasus ini karena ControllerBasesudah mengimplementasikannya.

<?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
sumber
Sudah cukup Anda memperpanjang ControllerBase; tidak perlu diterapkan ContainerInjectionInterfacekarena itu sudah dilakukan dariControllerBase .
kiamlaluno
@kiamlaluno, itu benar. kode Anda berfungsi sempurna.
ARUN