Completed
Push — master ( db6b00...5246ee )
by
unknown
08:09 queued 11s
created

OutputPageBeforeHTMLHookHandler::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 9.52
c 0
b 0
f 0
cc 1
nc 1
nop 11

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Wikibase\Repo\Hooks;
4
5
use MediaWiki\Hook\OutputPageBeforeHTMLHook;
6
use MediaWiki\MediaWikiServices;
7
use OutputPage;
8
use Wikibase\DataModel\Entity\EntityDocument;
9
use Wikibase\DataModel\Entity\EntityId;
10
use Wikibase\Lib\ContentLanguages;
11
use Wikibase\Lib\EntityFactory;
12
use Wikibase\Lib\LanguageNameLookup;
13
use Wikibase\Lib\Store\EntityRevision;
14
use Wikibase\Lib\Store\EntityRevisionLookup;
15
use Wikibase\Lib\UserLanguageLookup;
16
use Wikibase\Repo\BabelUserLanguageLookup;
17
use Wikibase\Repo\Hooks\Helpers\OutputPageEditability;
18
use Wikibase\Repo\Hooks\Helpers\OutputPageRevisionIdReader;
19
use Wikibase\Repo\Hooks\Helpers\UserPreferredContentLanguagesLookup;
20
use Wikibase\Repo\MediaWikiLanguageDirectionalityLookup;
21
use Wikibase\Repo\MediaWikiLocalizedTextProvider;
22
use Wikibase\Repo\ParserOutput\PlaceholderExpander\EntityViewPlaceholderExpander;
23
use Wikibase\Repo\ParserOutput\PlaceholderExpander\ExternallyRenderedEntityViewPlaceholderExpander;
24
use Wikibase\Repo\ParserOutput\PlaceholderExpander\PlaceholderExpander;
25
use Wikibase\Repo\ParserOutput\PlaceholderExpander\TermboxRequestInspector;
26
use Wikibase\Repo\ParserOutput\TermboxFlag;
27
use Wikibase\Repo\ParserOutput\TextInjector;
28
use Wikibase\Repo\View\RepoSpecialPageLinker;
29
use Wikibase\Repo\WikibaseRepo;
30
use Wikibase\View\Template\TemplateFactory;
31
use Wikibase\View\Termbox\Renderer\TermboxRemoteRenderer;
32
use Wikibase\View\ToolbarEditSectionGenerator;
33
34
/**
35
 * Handler for the "OutputPageBeforeHTML" hook.
36
 *
37
 * @license GPL-2.0-or-later
38
 * @author Marius Hoch < [email protected] >
39
 */
40
class OutputPageBeforeHTMLHookHandler implements OutputPageBeforeHTMLHook {
41
42
	/**
43
	 * @var TemplateFactory
44
	 */
45
	private $templateFactory;
46
47
	/**
48
	 * @var UserLanguageLookup
49
	 */
50
	private $userLanguageLookup;
51
52
	/**
53
	 * @var ContentLanguages
54
	 */
55
	private $termsLanguages;
56
57
	/**
58
	 * @var EntityRevisionLookup
59
	 */
60
	private $entityRevisionLookup;
61
62
	/**
63
	 * @var LanguageNameLookup
64
	 */
65
	private $languageNameLookup;
66
67
	/**
68
	 * @var OutputPageEntityIdReader
69
	 */
70
	private $outputPageEntityIdReader;
71
72
	/**
73
	 * @var EntityFactory
74
	 */
75
	private $entityFactory;
76
77
	/**
78
	 * @var string
79
	 */
80
	private $cookiePrefix;
81
82
	/**
83
	 * @var OutputPageEditability
84
	 */
85
	private $editability;
86
87
	/**
88
	 * @var bool
89
	 */
90
	private $isExternallyRendered;
91
92
	/**
93
	 * @var UserPreferredContentLanguagesLookup
94
	 */
95
	private $userPreferredTermsLanguages;
96
97
	public function __construct(
98
		TemplateFactory $templateFactory,
99
		UserLanguageLookup $userLanguageLookup,
100
		ContentLanguages $termsLanguages,
101
		EntityRevisionLookup $entityRevisionLookup,
102
		LanguageNameLookup $languageNameLookup,
103
		OutputPageEntityIdReader $outputPageEntityIdReader,
104
		EntityFactory $entityFactory,
105
		$cookiePrefix,
106
		OutputPageEditability $editability,
107
		$isExternallyRendered,
108
		UserPreferredContentLanguagesLookup $userPreferredTermsLanguages
109
	) {
110
		$this->templateFactory = $templateFactory;
111
		$this->userLanguageLookup = $userLanguageLookup;
112
		$this->termsLanguages = $termsLanguages;
113
		$this->entityRevisionLookup = $entityRevisionLookup;
114
		$this->languageNameLookup = $languageNameLookup;
115
		$this->outputPageEntityIdReader = $outputPageEntityIdReader;
116
		$this->entityFactory = $entityFactory;
117
		$this->cookiePrefix = $cookiePrefix;
118
		$this->isExternallyRendered = $isExternallyRendered;
119
		$this->editability = $editability;
120
		$this->userPreferredTermsLanguages = $userPreferredTermsLanguages;
121
	}
122
123
	/**
124
	 * @return self
125
	 */
126
	public static function factory(): self {
127
		global $wgLang, $wgCookiePrefix;
128
129
		$wikibaseRepo = WikibaseRepo::getDefaultInstance();
130
		$termLanguages = $wikibaseRepo->getTermsLanguages();
131
		$babelUserLanguageLookup = new BabelUserLanguageLookup();
132
133
		return new self(
134
			TemplateFactory::getDefaultInstance(),
135
			$babelUserLanguageLookup,
136
			$termLanguages,
137
			$wikibaseRepo->getEntityRevisionLookup(),
138
			new LanguageNameLookup( $wgLang->getCode() ),
139
			new OutputPageEntityIdReader(
140
				$wikibaseRepo->getEntityContentFactory(),
141
				$wikibaseRepo->getEntityIdParser()
142
			),
143
			$wikibaseRepo->getEntityFactory(),
144
			$wgCookiePrefix,
145
			new OutputPageEditability(),
146
			TermboxFlag::getInstance()->shouldRenderTermbox(),
147
			new UserPreferredContentLanguagesLookup(
148
				$termLanguages,
149
				$babelUserLanguageLookup,
150
				MediaWikiServices::getInstance()->getContentLanguage()->getCode()
151
			)
152
		);
153
	}
154
155
	/**
156
	 * Called when pushing HTML from the ParserOutput into OutputPage.
157
	 * Used to expand any placeholders in the OutputPage's 'wb-placeholders' property
158
	 * in the HTML.
159
	 *
160
	 * @param OutputPage $out
161
	 * @param string &$html the HTML to mangle
162
	 */
163
	public function onOutputPageBeforeHTML( $out, &$html ): void {
164
		if ( !$out->isArticle() ) {
165
			return;
166
		}
167
168
		$html = $this->replacePlaceholders( $out, $html );
169
		$this->addJsUserLanguages( $out );
170
		$html = $this->showOrHideEditLinks( $out, $html );
171
		$this->addTermboxModules( $out );
172
	}
173
174
	private function addTermboxModules( OutputPage $out ) {
175
		if ( $this->isExternallyRendered ) {
176
			$out->addModules( 'wikibase.termbox' );
177
			$out->addModuleStyles( [ 'wikibase.termbox.styles' ] );
178
		}
179
	}
180
181
	/**
182
	 * @param OutputPage $out
183
	 * @param string $html
184
	 *
185
	 * @return string
186
	 */
187
	private function replacePlaceholders( OutputPage $out, $html ) {
188
		$placeholders = $out->getProperty( 'wikibase-view-chunks' );
189
		if ( !$placeholders ) {
190
			return $html;
191
		}
192
193
		$injector = new TextInjector( $placeholders );
194
		$getHtmlCallback = function() {
195
			return '';
196
		};
197
198
		$entity = $this->getEntity( $out );
199
		if ( $entity instanceof EntityDocument ) {
200
			$getHtmlCallback = [ $this->getPlaceholderExpander( $entity, $out ), 'getHtmlForPlaceholder' ];
201
		}
202
203
		return $injector->inject( $html, $getHtmlCallback );
204
	}
205
206
	private function addJsUserLanguages( OutputPage $out ) {
207
		$out->addJsConfigVars(
208
			'wbUserSpecifiedLanguages',
209
			// All user-specified languages, that are valid term languages
210
			// Reindex the keys so that JavaScript still works if an unknown
211
			// language code in the babel box causes an index to miss
212
			array_values( array_intersect(
213
				$this->userLanguageLookup->getUserSpecifiedLanguages( $out->getUser() ),
214
				$this->termsLanguages->getLanguages()
215
			) )
216
		);
217
	}
218
219
	/**
220
	 * @param OutputPage $out
221
	 *
222
	 * @return EntityDocument|null
223
	 */
224
	private function getEntity( OutputPage $out ) {
225
		$entityId = $this->getEntityId( $out );
226
227
		if ( !$entityId ) {
228
			return null;
229
		}
230
231
		if ( $this->needsRealEntity( $out ) ) {
232
			// The parser cache content is too old to contain the terms list items
233
			// Pass the correct entity to generate terms list items on the fly
234
			$entityRev = $this->entityRevisionLookup->getEntityRevision( $entityId, $out->getRevisionId() );
235
			if ( !( $entityRev instanceof EntityRevision ) ) {
236
				return null;
237
			}
238
239
			return $entityRev->getEntity();
240
		}
241
242
		return $this->entityFactory->newEmpty( $entityId->getEntityType() );
243
	}
244
245
	private function needsRealEntity( OutputPage $out ) {
246
		return !$this->isExternallyRendered && !$this->getEntityTermsListHtml( $out );
247
	}
248
249
	private function getPlaceholderExpander(
250
		EntityDocument $entity,
251
		OutputPage $out
252
	): PlaceholderExpander {
253
		return $this->isExternallyRendered
254
			? $this->getExternallyRenderedEntityViewPlaceholderExpander( $out )
255
			: $this->getLocallyRenderedEntityViewPlaceholderExpander(
256
				$entity,
257
				$out
258
			);
259
	}
260
261
	/**
262
	 * @param EntityDocument $entity
263
	 * @param OutputPage $out
264
	 *
265
	 * @return EntityViewPlaceholderExpander
266
	 */
267
	private function getLocallyRenderedEntityViewPlaceholderExpander(
268
		EntityDocument $entity,
269
		OutputPage $out
270
	) {
271
		$language = $out->getLanguage();
272
		$user = $out->getUser();
273
274
		return new EntityViewPlaceholderExpander(
275
			$this->templateFactory,
276
			$user,
277
			$entity,
278
			$this->userPreferredTermsLanguages->getLanguages( $language->getCode(), $user ),
279
			new MediaWikiLanguageDirectionalityLookup(),
280
			$this->languageNameLookup,
281
			new MediaWikiLocalizedTextProvider( $language ),
282
			$this->cookiePrefix,
283
			$this->getEntityTermsListHtml( $out ) ?: []
284
		);
285
	}
286
287
	private function getExternallyRenderedEntityViewPlaceholderExpander( OutputPage $out ) {
288
		$repo = WikibaseRepo::getDefaultInstance();
289
		$languageFallbackChainFactory = $repo->getLanguageFallbackChainFactory();
290
291
		return new ExternallyRenderedEntityViewPlaceholderExpander(
292
			$out,
293
			new TermboxRequestInspector( $languageFallbackChainFactory ),
294
			new TermboxRemoteRenderer(
295
				MediaWikiServices::getInstance()->getHttpRequestFactory(),
296
				$repo->getSettings()->getSetting( 'ssrServerUrl' ),
297
				$repo->getSettings()->getSetting( 'ssrServerTimeout' ),
298
				$repo->getLogger(),
299
				MediaWikiServices::getInstance()->getStatsdDataFactory()
300
			),
301
			$this->outputPageEntityIdReader,
302
			new RepoSpecialPageLinker(),
303
			$languageFallbackChainFactory,
304
			new OutputPageRevisionIdReader(),
305
			$repo->getSettings()->getSetting( 'termboxUserSpecificSsrEnabled' )
306
		);
307
	}
308
309
	private function getEntityTermsListHtml( OutputPage $out ) {
310
		return $out->getProperty( 'wikibase-terms-list-items' );
311
	}
312
313
	private function showOrHideEditLinks( OutputPage $out, $html ) {
314
		return ToolbarEditSectionGenerator::enableSectionEditLinks(
315
			$html,
316
			$this->editability->validate( $out )
317
		);
318
	}
319
320
	/**
321
	 * @param OutputPage $out
322
	 *
323
	 * @return EntityId|null
324
	 */
325
	private function getEntityId( OutputPage $out ) {
326
		return $this->outputPageEntityIdReader->getEntityIdFromOutputPage( $out );
327
	}
328
329
}
330