Completed
Push — master ( 951284...b5c57e )
by
unknown
06:36 queued 11s
created

client/includes/ClientHooks.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Wikibase\Client;
4
5
use Action;
6
use MediaWiki\MediaWikiServices;
7
use Skin;
8
use Title;
9
use User;
10
use Wikibase\Client\DataAccess\Scribunto\Scribunto_LuaWikibaseEntityLibrary;
11
use Wikibase\Client\DataAccess\Scribunto\Scribunto_LuaWikibaseLibrary;
12
use Wikibase\Client\Hooks\SkinAfterBottomScriptsHandler;
13
use Wikibase\DataModel\Entity\EntityId;
14
use Wikibase\DataModel\Entity\EntityIdParsingException;
15
use Wikibase\Lib\Formatters\AutoCommentFormatter;
16
17
/**
18
 * File defining the hook handlers for the Wikibase Client extension.
19
 *
20
 * @license GPL-2.0-or-later
21
 */
22
final class ClientHooks {
23
24
	/**
25
	 * @see NamespaceChecker::isWikibaseEnabled
26
	 *
27
	 * @param int $namespace
28
	 *
29
	 * @return bool
30
	 */
31
	protected static function isWikibaseEnabled( $namespace ) {
32
		return WikibaseClient::getDefaultInstance()->getNamespaceChecker()->isWikibaseEnabled( $namespace );
33
	}
34
35
	/**
36
	 * External library for Scribunto
37
	 *
38
	 * @param string $engine
39
	 * @param string[] &$extraLibraries
40
	 */
41
	public static function onScribuntoExternalLibraries( $engine, array &$extraLibraries ) {
42
		$allowDataTransclusion = WikibaseClient::getDefaultInstance()->getSettings()->getSetting( 'allowDataTransclusion' );
43
		if ( $engine == 'lua' && $allowDataTransclusion === true ) {
44
			$extraLibraries['mw.wikibase'] = Scribunto_LuaWikibaseLibrary::class;
45
			$extraLibraries['mw.wikibase.entity'] = Scribunto_LuaWikibaseEntityLibrary::class;
46
		}
47
	}
48
49
	/**
50
	 * Handler for the FormatAutocomments hook, implementing localized formatting
51
	 * for machine readable autocomments generated by SummaryFormatter.
52
	 *
53
	 * @param string &$comment reference to the autocomment text
54
	 * @param bool $pre true if there is content before the autocomment
55
	 * @param string $auto the autocomment unformatted
56
	 * @param bool $post true if there is content after the autocomment
57
	 * @param Title|null $title use for further information
58
	 * @param bool $local shall links be generated locally or globally
59
	 * @param string|null $wikiId The ID of the wiki the comment applies to, if not the local wiki.
60
	 */
61
	public static function onFormat( &$comment, $pre, $auto, $post, $title, $local, $wikiId = null ) {
0 ignored issues
show
The parameter $title is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $local is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
62
		$wikibaseClient = WikibaseClient::getDefaultInstance();
63
		$repoId = $wikibaseClient->getSettings()->getSetting( 'repoSiteId' );
64
65
		// Only do special formatting for comments from a wikibase repo.
66
		// XXX: what to do if the local wiki is the repo? For entity pages, RepoHooks has a handler.
67
		// But what to do for other pages? Note that if the local wiki is the repo, $repoId will be
68
		// false, and $wikiId will be null.
69
		if ( $wikiId !== $repoId ) {
70
			return;
71
		}
72
73
		$formatter = new AutoCommentFormatter(
74
			MediaWikiServices::getInstance()->getContentLanguage(),
75
			[ 'wikibase-entity' ]
76
		);
77
		$formattedComment = $formatter->formatAutoComment( $auto );
78
79
		if ( is_string( $formattedComment ) ) {
80
			$comment = $formatter->wrapAutoComment( $pre, $formattedComment, $post );
81
		}
82
	}
83
84
	/**
85
	 * Build 'Wikidata item' link for later addition to the toolbox section of the sidebar
86
	 *
87
	 * @param Skin $skin
88
	 *
89
	 * @return string[]|null Array of link elements or Null if link cannot be created.
90
	 */
91
	public static function buildWikidataItemLink( Skin $skin ): ?array {
92
		$wbClient = WikibaseClient::getDefaultInstance();
93
		$title = $skin->getTitle();
94
		$idString = $skin->getOutput()->getProperty( 'wikibase_item' );
95
		$entityId = null;
96
97
		if ( $idString !== null ) {
98
			$entityIdParser = $wbClient->getEntityIdParser();
99
			$entityId = $entityIdParser->parse( $idString );
100
		} elseif ( $title &&
101
			Action::getActionName( $skin->getContext() ) !== 'view' && $title->exists()
102
		) {
103
			// Try to load the item ID from Database, but only do so on non-article views,
104
			// (where the article's OutputPage isn't available to us).
105
			$entityId = self::getEntityIdForTitle( $title, $wbClient );
106
		}
107
108
		if ( $entityId !== null ) {
109
			$repoLinker = $wbClient->newRepoLinker();
110
111
			return [
112
				'id' => 't-wikibase',
113
				'text' => $skin->msg( 'wikibase-dataitem' )->text(),
114
				'href' => $repoLinker->getEntityUrl( $entityId ),
115
			];
116
		}
117
118
		return null;
119
	}
120
121
	/**
122
	 * @param Title $title
123
	 * @param WikibaseClient $wbClient
124
	 *
125
	 * @return EntityId|null
126
	 */
127
	private static function getEntityIdForTitle( Title $title, WikibaseClient $wbClient ): ?EntityId {
128
		if ( !self::isWikibaseEnabled( $title->getNamespace() ) ) {
129
			return null;
130
		}
131
132
		$entityIdLookup = $wbClient->getEntityIdLookup();
133
		return $entityIdLookup->getEntityIdForTitle( $title );
134
	}
135
136
	/**
137
	 * Adds a preference for showing or hiding Wikidata entries in recent changes
138
	 *
139
	 * @param User $user
140
	 * @param array[] &$prefs
141
	 */
142
	public static function onGetPreferences( User $user, array &$prefs ) {
0 ignored issues
show
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
143
		$settings = WikibaseClient::getDefaultInstance()->getSettings();
144
145
		if ( !$settings->getSetting( 'showExternalRecentChanges' ) ) {
146
			return;
147
		}
148
149
		$prefs['rcshowwikidata'] = [
150
			'type' => 'toggle',
151
			'label-message' => 'wikibase-rc-show-wikidata-pref',
152
			'section' => 'rc/advancedrc',
153
		];
154
155
		$prefs['wlshowwikibase'] = [
156
			'type' => 'toggle',
157
			'label-message' => 'wikibase-watchlist-show-changes-pref',
158
			'section' => 'watchlist/advancedwatchlist',
159
		];
160
	}
161
162
	/**
163
	 * Add morelikewithwikibase keyword.
164
	 * @param $config
165
	 * @param array &$extraFeatures
166
	 */
167
	public static function onCirrusSearchAddQueryFeatures(
168
		$config,
169
		array &$extraFeatures
170
	) {
171
		$extraFeatures[] = new MoreLikeWikibase( $config );
172
	}
173
174
	/**
175
	 * Injects a Wikidata inline JSON-LD script schema for search engine optimization.
176
	 *
177
	 * @param Skin $skin
178
	 * @param string &$html
179
	 *
180
	 * @return bool Always true.
181
	 */
182
	public static function onSkinAfterBottomScripts( Skin $skin, &$html ) {
183
		$client = WikibaseClient::getDefaultInstance();
184
		$enabledNamespaces = $client->getSettings()->getSetting( 'pageSchemaNamespaces' );
185
186
		$out = $skin->getOutput();
187
		$entityId = self::parseEntityId( $client, $out->getProperty( 'wikibase_item' ) );
188
		$title = $out->getTitle();
189
		if (
190
			!$entityId ||
191
			!$title ||
192
			!in_array( $title->getNamespace(), $enabledNamespaces ) ||
193
			!$title->exists()
194
		) {
195
			return true;
196
		}
197
198
		$handler = new SkinAfterBottomScriptsHandler( $client, $client->newRepoLinker() );
199
		$revisionTimestamp = $out->getRevisionTimestamp();
200
		$html .= $handler->createSchemaElement(
201
			$title,
202
			$revisionTimestamp,
203
			$entityId
204
		);
205
206
		return true;
207
	}
208
209
	/**
210
	 * @param WikibaseClient $client
211
	 * @param string|null $prefixedId
212
	 *
213
	 * @return EntityId|null
214
	 */
215
	private static function parseEntityId( WikibaseClient $client, $prefixedId = null ) {
216
		if ( !$prefixedId ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $prefixedId of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
217
			return null;
218
		}
219
220
		try {
221
			return $client->getEntityIdParser()->parse( $prefixedId );
222
		} catch ( EntityIdParsingException $ex ) {
223
			return null;
224
		}
225
	}
226
227
	/**
228
	 * Used to propagate information about the current site to JavaScript.
229
	 * This is used in "wikibase.client.linkitem.init" module
230
	 */
231
	public static function getSiteConfiguration() {
232
		$cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
233
		$key = $cache->makeKey(
234
			'wikibase-client',
235
			'siteConfiguration'
236
		);
237
		return $cache->getWithSetCallback(
238
			$key,
239
			$cache::TTL_DAY,
240
			function () {
241
				$wikibaseClient = WikibaseClient::getDefaultInstance();
242
243
				$site = $wikibaseClient->getSite();
244
				$currentSite = [
245
					'globalSiteId' => $site->getGlobalId(),
246
					'languageCode' => $site->getLanguageCode(),
247
					'langLinkSiteGroup' => $wikibaseClient->getLangLinkSiteGroup()
248
				];
249
250
				return [ 'currentSite' => $currentSite ];
251
			},
252
			// @fixme These options only exist in WanObjectCache, but this code is using BagOStuff!
253
			// @phan-suppress-next-line PhanTypeMismatchArgument
254
			[ 'lockTSE' => 10, 'pcTTL' => $cache::TTL_PROC_LONG ]
255
		);
256
	}
257
258
}
259