UpdateRepoHookHandler::factory()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Wikibase\Client\Hooks;
4
5
use Content;
6
use JobQueueGroup;
7
use LogEntry;
8
use MediaWiki\Hook\PageMoveCompleteHook;
9
use MediaWiki\Linker\LinkTarget;
10
use MediaWiki\Logger\LoggerFactory;
11
use MediaWiki\Page\Hook\ArticleDeleteCompleteHook;
12
use MediaWiki\Revision\RevisionRecord;
13
use MediaWiki\User\UserIdentity;
14
use MWException;
15
use Psr\Log\LoggerInterface;
16
use Title;
17
use User;
18
use Wikibase\Client\NamespaceChecker;
19
use Wikibase\Client\UpdateRepo\UpdateRepoOnDelete;
20
use Wikibase\Client\UpdateRepo\UpdateRepoOnMove;
21
use Wikibase\Client\WikibaseClient;
22
use Wikibase\Lib\Store\SiteLinkLookup;
23
use WikiPage;
24
25
/**
26
 * This class has a static interface for use with MediaWiki's hook mechanism; the static
27
 * handler functions will create a new instance of UpdateRepoHookHandlers and then call the
28
 * corresponding member function on that.
29
 *
30
 * @license GPL-2.0-or-later
31
 * @author Marius Hoch < [email protected] >
32
 */
33
class UpdateRepoHookHandler implements PageMoveCompleteHook, ArticleDeleteCompleteHook {
34
35
	/**
36
	 * @var NamespaceChecker
37
	 */
38
	private $namespaceChecker;
39
40
	/**
41
	 * @var JobQueueGroup
42
	 */
43
	private $jobQueueGroup;
44
45
	/**
46
	 * @var SiteLinkLookup
47
	 */
48
	private $siteLinkLookup;
49
50
	/**
51
	 * @var LoggerInterface
52
	 */
53
	private $logger;
54
55
	/**
56
	 * @var string
57
	 */
58
	private $repoDatabase;
59
60
	/**
61
	 * @var string
62
	 */
63
	private $siteGlobalID;
64
65
	/**
66
	 * @var bool
67
	 */
68
	private $propagateChangesToRepo;
69
70
	/**
71
	 * @return self|null
72
	 */
73
	public static function factory() {
74
		$wikibaseClient = WikibaseClient::getDefaultInstance();
75
		$settings = $wikibaseClient->getSettings();
76
77
		$namespaceChecker = $wikibaseClient->getNamespaceChecker();
78
79
		$repoDB = $wikibaseClient->getDatabaseDomainNameOfLocalRepo();
80
		$jobQueueGroup = JobQueueGroup::singleton( $repoDB );
81
82
		if ( !$jobQueueGroup ) {
83
			wfLogWarning( "Failed to acquire a JobQueueGroup for $repoDB" );
84
			return null;
85
		}
86
87
		$siteLinkLookup = $wikibaseClient->getStore()->getSiteLinkLookup();
88
89
		return new self(
90
			$namespaceChecker,
91
			$jobQueueGroup,
92
			$siteLinkLookup,
93
			LoggerFactory::getInstance( 'UpdateRepo' ),
94
			$repoDB,
95
			$settings->getSetting( 'siteGlobalID' ),
96
			$settings->getSetting( 'propagateChangesToRepo' )
97
		);
98
	}
99
100
	/**
101
	 * @param NamespaceChecker $namespaceChecker
102
	 * @param JobQueueGroup $jobQueueGroup
103
	 * @param SiteLinkLookup $siteLinkLookup
104
	 * @param LoggerInterface $logger
105
	 * @param string $repoDatabase
106
	 * @param string $siteGlobalID
107
	 * @param bool $propagateChangesToRepo
108
	 */
109
	public function __construct(
110
		NamespaceChecker $namespaceChecker,
111
		JobQueueGroup $jobQueueGroup,
112
		SiteLinkLookup $siteLinkLookup,
113
		LoggerInterface $logger,
114
		$repoDatabase,
115
		$siteGlobalID,
116
		$propagateChangesToRepo
117
	) {
118
		$this->namespaceChecker = $namespaceChecker;
119
		$this->jobQueueGroup = $jobQueueGroup;
120
		$this->siteLinkLookup = $siteLinkLookup;
121
		$this->logger = $logger;
122
123
		$this->repoDatabase = $repoDatabase;
124
		$this->siteGlobalID = $siteGlobalID;
125
		$this->propagateChangesToRepo = $propagateChangesToRepo;
126
	}
127
128
	/**
129
	 * @see NamespaceChecker::isWikibaseEnabled
130
	 *
131
	 * @param int $namespace
132
	 *
133
	 * @return bool
134
	 */
135
	private function isWikibaseEnabled( $namespace ) {
136
		return $this->namespaceChecker->isWikibaseEnabled( $namespace );
137
	}
138
139
	/**
140
	 * After a page has been deleted also update the item on the repo.
141
	 * This only works if there's a user account with the same name on the repo.
142
	 *
143
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleDeleteComplete
144
	 *
145
	 * @param WikiPage $wikiPage WikiPage that was deleted
146
	 * @param User $user User that deleted the article
147
	 * @param string $reason Reason the article was deleted
148
	 * @param int $id ID of the article that was deleted
149
	 * @param Content|null $content Content of the deleted page (or null, when deleting a broken page)
150
	 * @param \ManualLogEntry $logEntry ManualLogEntry used to record the deletion
151
	 * @param int $archivedRevisionCount Number of revisions archived during the deletion
152
	 * @return bool|void True or no return value to continue or false to abort
153
	 */
154
	public function onArticleDeleteComplete(
155
		$wikiPage,
156
		$user,
157
		$reason,
158
		$id,
159
		$content,
160
		$logEntry,
161
		$archivedRevisionCount
162
	) {
163
		if ( $this->propagateChangesToRepo !== true ) {
164
			return true;
165
		}
166
167
		$updateRepo = new UpdateRepoOnDelete(
168
			$this->repoDatabase,
169
			$this->siteLinkLookup,
170
			$this->logger,
171
			$user,
172
			$this->siteGlobalID,
173
			$wikiPage->getTitle()
174
		);
175
176
		if ( !$updateRepo->isApplicable() ) {
177
			return true;
178
		}
179
180
		try {
181
			$updateRepo->injectJob( $this->jobQueueGroup );
182
183
			// To be able to find out about this in the ArticleDeleteAfter hook
184
			// @phan-suppress-next-line PhanUndeclaredProperty Dynamic property
185
			$wikiPage->getTitle()->wikibasePushedDeleteToRepo = true;
186
		} catch ( MWException $e ) {
0 ignored issues
show
Bug introduced by
The class MWException does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
187
			// This is not a reason to let an exception bubble up, we just
188
			// show a message to the user that the Wikibase item needs to be
189
			// manually updated.
190
			wfLogWarning( $e->getMessage() );
191
192
			$this->logger->debug(
193
				'{method}: Failed to inject job: "{msg}"!',
194
				[
195
					'method' => __METHOD__,
196
					'msg' => $e->getMessage()
197
				]
198
			);
199
200
		}
201
202
		return true;
203
	}
204
205
	/**
206
	 * After a page has been moved also update the item on the repo.
207
	 * This only works if there's a user account with the same name on the repo.
208
	 *
209
	 * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageMoveComplete
210
	 *
211
	 * @param LinkTarget $oldLinkTarget
212
	 * @param LinkTarget $newLinkTarget
213
	 * @param UserIdentity $userIdentity
214
	 * @param int $pageId database ID of the page that's been moved
215
	 * @param int $redirid ID of the created redirect
216
	 * @param string $reason
217
	 * @param RevisionRecord $revisionRecord revision created by the move
218
	 *
219
	 * @return bool
220
	 */
221
	public function onPageMoveComplete(
222
		$oldLinkTarget,
223
		$newLinkTarget,
224
		$userIdentity,
225
		$pageId,
226
		$redirid,
227
		$reason,
228
		$revisionRecord
229
	) {
230
		if ( !$this->isWikibaseEnabled( $newLinkTarget->getNamespace() ) ) {
231
			return true;
232
		}
233
234
		if ( $this->propagateChangesToRepo !== true ) {
235
			return true;
236
		}
237
238
		$old = Title::newFromLinkTarget( $oldLinkTarget );
239
		$nt = Title::newFromLinkTarget( $newLinkTarget );
240
		$user = User::newFromIdentity( $userIdentity );
241
242
		$updateRepo = new UpdateRepoOnMove(
243
			$this->repoDatabase,
244
			$this->siteLinkLookup,
245
			$this->logger,
246
			$user,
247
			$this->siteGlobalID,
248
			$old,
249
			$nt
250
		);
251
252
		if ( !$updateRepo->isApplicable() ) {
253
			return true;
254
		}
255
256
		try {
257
			$updateRepo->injectJob( $this->jobQueueGroup );
258
259
			// To be able to find out about this in the SpecialMovepageAfterMove hook
260
			// @phan-suppress-next-line PhanUndeclaredProperty Dynamic property
261
			$nt->wikibasePushedMoveToRepo = true;
262
		} catch ( MWException $e ) {
0 ignored issues
show
Bug introduced by
The class MWException does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
263
			// This is not a reason to let an exception bubble up, we just
264
			// show a message to the user that the Wikibase item needs to be
265
			// manually updated.
266
			wfLogWarning( $e->getMessage() );
267
268
			$this->logger->debug(
269
				'{method}: Failed to inject job: "{msg}"!',
270
				[
271
					'method' => __METHOD__,
272
					'msg' => $e->getMessage()
273
				]
274
			);
275
		}
276
277
		return true;
278
	}
279
280
}
281