1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
<?php
namespace Drupal\help;
use Drupal\Component\FrontMatter\FrontMatter;
use Drupal\Component\Serialization\Exception\InvalidDataTypeException;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Extension\ThemeHandlerInterface;
use Drupal\Core\Serialization\Yaml;
use Twig\Error\LoaderError;
use Twig\Loader\FilesystemLoader;
use Twig\Source;
/**
* Loads help topic Twig files from the filesystem.
*
* This loader adds module and theme help topic paths to a help_topics namespace
* to the Twig filesystem loader so that help_topics can be referenced, using
* '@help-topic/pluginId.html.twig'.
*
* @see \Drupal\help\HelpTopicDiscovery
* @see \Drupal\help\HelpTopicTwig
*
* @internal
* Tagged services are internal.
*/
class HelpTopicTwigLoader extends FilesystemLoader {
/**
* {@inheritdoc}
*/
const MAIN_NAMESPACE = 'help_topics';
/**
* Constructs a new HelpTopicTwigLoader object.
*
* @param string $root_path
* The root path.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler service.
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
* The theme handler service.
*/
public function __construct($root_path, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler) {
parent::__construct([], $root_path);
// Add help_topics directories for modules and themes in the 'help_topic'
// namespace, plus core.
$this->addExtension($root_path . '/core');
array_map([$this, 'addExtension'], $module_handler->getModuleDirectories());
array_map([$this, 'addExtension'], $theme_handler->getThemeDirectories());
}
/**
* Adds an extensions help_topics directory to the Twig loader.
*
* @param string $path
* The path to the extension.
*/
protected function addExtension($path) {
$path .= DIRECTORY_SEPARATOR . 'help_topics';
if (is_dir($path)) {
$this->cache = $this->errorCache = [];
$this->paths[self::MAIN_NAMESPACE][] = rtrim($path, '/\\');
}
}
/**
* {@inheritdoc}
*/
public function getSourceContext(string $name): Source {
$path = $this->findTemplate($name);
$contents = file_get_contents($path);
try {
// Note: always use \Drupal\Core\Serialization\Yaml here instead of the
// "serializer.yaml" service. This allows the core serializer to utilize
// core related functionality which isn't available as the standalone
// component based serializer.
$front_matter = new FrontMatter($contents, Yaml::class);
// Reconstruct the content if there is front matter data detected. Prepend
// the source with {% line \d+ %} to inform Twig that the source code
// actually starts on a different line past the front matter data. This is
// particularly useful when used in error reporting.
if ($front_matter->getData() && ($line = $front_matter->getLine())) {
$contents = "{% line $line %}" . $front_matter->getContent();
}
}
catch (InvalidDataTypeException $e) {
throw new LoaderError(sprintf('Malformed YAML in help topic "%s": %s.', $path, $e->getMessage()));
}
return new Source($contents, $name, $path);
}
/**
* {@inheritdoc}
*/
protected function findTemplate($name, $throw = TRUE) {
if (!str_ends_with($name, '.html.twig')) {
if (!$throw) {
return NULL;
}
$extension = pathinfo($name, PATHINFO_EXTENSION);
throw new LoaderError(sprintf("Help topic %s has an invalid file extension (%s). Only help topics ending .html.twig are allowed.", $name, $extension));
}
return parent::findTemplate($name, $throw);
}
}
|