依赖注入到 Twig 扩展中

此示例将向你展示如何使用 Dependency Inject 来使用在 Drupal 环境中注册的其他服务。

想象一下,你有一个 SVG 图像文件,根据项目中的一些随机 CSS / Javascript 事情改变颜色。为了能够使用 CSS 定位 SVG,你必须在 DOM 中实际拥有 SVG 文件。因此,你创建一个没有任何颜色的基本 SVG 文件,并将其放在主题文件夹中。

当然,你可以将文件的内容粘贴到 Twig 模板中,但这样做并不好。你可以创建一个 Twig 扩展,但你也不想在扩展源代码中对主题路径进行硬编码。

这意味着我们必须动态获取路径。你有两个选择:

  1. 通过调用\Drupal::theme()->getActiveTheme()->getPath(); 使用等效于全局变量
  2. 在扩展类中注入 ThemeManager(由\Drupal::theme() 给出)

在本例中,我们将采用第二个示例,因为它可以广泛应用于任何服务(如果需要,可以导入请求或数据库连接)。

这假设你有一个名为 twig_svg_extensiontwig_svg_extension.services.yml 文件的模块:

services:
  twig_svg_extension.twig_extension:
    class: Drupal\twig_svg_extension\TwigExtension\TwigSvgExtension
    arguments: ['@theme.manager']
    tags:
      - { name: twig.extension }

请不要告诉 Drupal 注入服务的 arguments 密钥。

namespace Drupal\twig_svg_Extension\TwigExtension;

use Drupal\Core\Theme\ThemeManager;
use Twig_Extension;
use Twig_SimpleFilter;

class TwigSvgExtension extends Twig_Extension  {
  private $theme;
  
  // Dependency injection at work!
  public function __construct(ThemeManager $theme) {
    $this->theme = $theme;
  }

  public function getFilters() {
    return [
      'svg' =>new Twig_SimpleFilter('svg', [$this, 'svgFilter']),
    ];
  }

  public function getName() {
    return 'twig_svg_extension.twig_extension';
  }

  public function svgFilter(string $filepath) {
    $realpath = realpath($this->theme->getActiveTheme()->getPath().DIRECTORY_SEPARATOR.$filepath);
    $pathinfo = pathinfo($realpath);

    if($realpath !== false && strtolower($pathinfo['extension']) === 'svg') {
      return file_get_contents($realpath);
    }

    return '"'.$filepath.'" does not exist or is not an SVG';
  }
}

请注意构造函数,其中包含我们在服务配置中注入的依赖项以及获取当前活动主题路径的 svgFilter

$filepath 应该是你的主题文件夹的相对路径。扩展名将文件路径转换为它指向的文件的内容。