MediaWiki master
DefaultOutputPipelineFactory.php
Go to the documentation of this file.
1<?php
2declare( strict_types = 1 );
3
5
25use Psr\Log\LoggerInterface;
26use Wikimedia\ObjectFactory\ObjectFactory;
27
34
35 private ServiceOptions $options;
36 private Config $config;
37 private LoggerInterface $logger;
38 private ObjectFactory $objectFactory;
39
40 public const CONSTRUCTOR_OPTIONS = [
42 ];
43
44 private const CORE_LIST = [
45 'ExtractBody' => [
46 'class' => ExtractBody::class,
47 'services' => [
48 'UrlUtils',
49 ],
50 ],
51 'AddRedirectHeader' =>
52 AddRedirectHeader::class,
53
54 'RenderDebugInfo' => [
55 'class' => RenderDebugInfo::class,
56 'services' => [
57 'HookContainer',
58 ],
59 ],
60 'ExecutePostCacheTransformHooks' => [
61 'class' => ExecutePostCacheTransformHooks::class,
62 'services' => [
63 'HookContainer',
64 ],
65 ],
66 'AddWrapperDivClass' => [
67 'class' => AddWrapperDivClass::class,
68 'services' => [
69 'LanguageFactory',
70 'ContentLanguage',
71 ],
72 ],
73 // The next five stages are all DOM-based passes. They are adjacent to each
74 // other to be able to skip unnecessary intermediate DOM->text->DOM transformations.
75 'ExpandRelativeAttrs' => [
76 'class' => ExpandRelativeAttrs::class,
77 'services' => [
78 'UrlUtils',
79 'ParsoidSiteConfig',
80 ],
81 'optional_services' => [
82 'MobileFrontend.Context',
83 ],
84 ],
85 'HandleSectionLinks' => [
86 'textStage' => [
87 'class' => HandleSectionLinks::class,
88 'services' => [
89 'TitleFactory',
90 ],
91 ],
92 'domStage' => [
93 'class' => HandleParsoidSectionLinks::class,
94 'services' => [
95 'TitleFactory',
96 ],
97 ],
98 'exclusive' => true
99 ],
100 // This should be before DeduplicateStyles because some system messages may use TemplateStyles (so we
101 // want to expand them before deduplication).
102 'ParsoidLocalization' => [
103 'class' => ParsoidLocalization::class,
104 'services' => [
105 'TitleFactory',
106 'LanguageFactory',
107 ]
108 ],
109 'HandleTOCMarkers' => [
110 'textStage' => [
111 'class' => HandleTOCMarkersText::class,
112 'services' => [
113 'Tidy',
114 ],
115 ],
116 'domStage' => [
117 'class' => HandleTOCMarkersDOM::class
118 ],
119 'exclusive' => false
120 ],
121 'DeduplicateStyles' => [
122 'textStage' => [
123 'class' => DeduplicateStyles::class,
124 ],
125 'domStage' => [
126 'class' => DeduplicateStylesDOM::class,
127 ],
128 'exclusive' => false
129 ],
130
131 'ExpandToAbsoluteUrls' =>
132 ExpandToAbsoluteUrls::class,
133
134 'HydrateHeaderPlaceholders' =>
135 HydrateHeaderPlaceholders::class,
136
137 # This should be last, in order to ensure final output is hardened
138 'HardenNFC' =>
139 HardenNFC::class,
140 ];
141
142 public function __construct(
143 ServiceOptions $options,
144 Config $config,
145 LoggerInterface $logger,
146 ObjectFactory $objectFactory
147 ) {
148 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
149 $this->options = $options;
150 $this->config = $config;
151 $this->logger = $logger;
152 $this->objectFactory = $objectFactory;
153 }
154
162 // Add extension stages
163 $list = array_merge(
164 self::CORE_LIST,
165 $this->options->get( MainConfigNames::OutputPipelineStages )
166 );
167
168 $otp = new OutputTransformPipeline();
169 foreach ( $list as $spec ) {
170 if ( is_array( $spec ) &&
171 array_key_exists( 'domStage', $spec ) &&
172 array_key_exists( 'textStage', $spec )
173 ) {
174 $args = [
175 $this->objectFactory->createObject( $spec['textStage'],
176 [
177 'assertClass' => ContentTextTransformStage::class,
178 'allowClassName' => true,
179 ] + $this->makeExtraArgs( $spec['textStage'] ) ),
180 $this->objectFactory->createObject( $spec['domStage'],
181 [
182 'assertClass' => ContentDOMTransformStage::class,
183 'allowClassName' => true,
184 ] + $this->makeExtraArgs( $spec['domStage'] ) ),
185 $spec['exclusive'] ?? false
186 ];
187 $spec = [
188 'class' => ContentHolderTransformStage::class,
189 'args' => $args
190 ];
191 }
192
193 // ObjectFactory::createObject accepts an array, not just a callable (phan bug)
194 // @phan-suppress-next-line PhanTypeInvalidCallableArrayKey
195 $transform = $this->objectFactory->createObject(
196 $spec,
197 [
198 'assertClass' => OutputTransformStage::class,
199 'allowClassName' => true,
200 ] + $this->makeExtraArgs( $spec )
201 );
202 $otp->addStage( $transform );
203 }
204 return $otp;
205 }
206
212 private function makeExtraArgs( $spec ): array {
213 // If the handler is specified as a class, use the CONSTRUCTOR_OPTIONS
214 // for that class.
215 $class = is_string( $spec ) ? $spec : ( $spec['class'] ?? null );
216 $svcOptions = new ServiceOptions(
217 $class ? $class::CONSTRUCTOR_OPTIONS : [],
218 $this->config
219 );
220 return [ 'extraArgs' => [ $svcOptions, $this->logger ] ];
221 }
222}
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
A class containing constants representing the names of configuration variables.
const OutputPipelineStages
Name constant for the OutputPipelineStages setting, for use with Config::get()
This class contains the default output transformation pipeline factory for wikitext.
buildPipeline()
Creates a pipeline of transformations to transform the content of the ParserOutput object from "parse...
__construct(ServiceOptions $options, Config $config, LoggerInterface $logger, ObjectFactory $objectFactory)
Wrap the output in a div with the provided class name.
Generates a list of unique style links.
Applies base href to relative urls in attributes.
Strip everything but the <body>
Inject table of contents (or empty string if there's no sections)
Hardens the output against NFC normalization (T387130).
Definition HardenNFC.php:15
Hydrate slot section header placeholders generated by RevisionRenderer.
Resolves the mw:I18n and mw:LocalizedAttrs to their localised forms.
Interface for configuration instances.
Definition Config.php:18