1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Wikibase\Repo\UpdateRepo; |
4
|
|
|
|
5
|
|
|
use MediaWiki\Logger\LoggerFactory; |
6
|
|
|
use OutOfBoundsException; |
7
|
|
|
use Psr\Log\LoggerInterface; |
8
|
|
|
use SiteLookup; |
9
|
|
|
use Title; |
10
|
|
|
use Wikibase\DataModel\Entity\Item; |
11
|
|
|
use Wikibase\DataModel\Services\Lookup\EntityLookup; |
12
|
|
|
use Wikibase\DataModel\SiteLink; |
13
|
|
|
use Wikibase\Lib\Store\EntityStore; |
14
|
|
|
use Wikibase\Lib\Store\LookupConstants; |
15
|
|
|
use Wikibase\Lib\Summary; |
16
|
|
|
use Wikibase\Repo\EditEntity\MediawikiEditEntityFactory; |
17
|
|
|
use Wikibase\Repo\Store\Store; |
18
|
|
|
use Wikibase\Repo\SummaryFormatter; |
19
|
|
|
use Wikibase\Repo\WikibaseRepo; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Job for updating the repo after a page on the client has been moved. |
23
|
|
|
* |
24
|
|
|
* @license GPL-2.0-or-later |
25
|
|
|
* @author Marius Hoch < [email protected] > |
26
|
|
|
*/ |
27
|
|
|
class UpdateRepoOnMoveJob extends UpdateRepoJob { |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var SiteLookup |
31
|
|
|
*/ |
32
|
|
|
private $siteLookup; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var string|bool|null |
36
|
|
|
*/ |
37
|
|
|
private $normalizedPageName = null; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Constructs a UpdateRepoOnMoveJob propagating a page move to the repo |
41
|
|
|
* |
42
|
|
|
* @note This is for use by Job::factory, don't call it directly; |
43
|
|
|
* use newFrom*() instead. |
44
|
|
|
* |
45
|
|
|
* @note the constructor's signature is dictated by Job::factory, so we'll have to |
46
|
|
|
* live with it even though it's rather ugly for our use case. |
47
|
|
|
* |
48
|
|
|
* @see Job::factory |
49
|
|
|
* @see UpdateRepoJob::__construct |
50
|
|
|
* |
51
|
|
|
* @param Title $title |
52
|
|
|
* @param array $params |
53
|
|
|
*/ |
54
|
|
|
public function __construct( Title $title, array $params = [] ) { |
55
|
|
|
parent::__construct( 'UpdateRepoOnMove', $title, $params ); |
56
|
|
|
|
57
|
|
|
$this->initRepoJobServicesFromGlobalState(); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
protected function initRepoJobServicesFromGlobalState() { |
61
|
|
|
$wikibaseRepo = WikibaseRepo::getDefaultInstance(); |
62
|
|
|
$this->initServices( |
63
|
|
|
$wikibaseRepo->getEntityLookup( Store::LOOKUP_CACHING_DISABLED, LookupConstants::LATEST_FROM_MASTER ), |
64
|
|
|
$wikibaseRepo->getEntityStore(), |
65
|
|
|
$wikibaseRepo->getSummaryFormatter(), |
66
|
|
|
LoggerFactory::getInstance( 'UpdateRepo' ), |
67
|
|
|
$wikibaseRepo->getSiteLookup(), |
68
|
|
|
$wikibaseRepo->newEditEntityFactory() |
69
|
|
|
); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
public function initServices( |
73
|
|
|
EntityLookup $entityLookup, |
74
|
|
|
EntityStore $entityStore, |
75
|
|
|
SummaryFormatter $summaryFormatter, |
76
|
|
|
LoggerInterface $logger, |
77
|
|
|
SiteLookup $siteLookup, |
78
|
|
|
MediawikiEditEntityFactory $editEntityFactory |
79
|
|
|
) { |
80
|
|
|
$this->initRepoJobServices( |
81
|
|
|
$entityLookup, |
82
|
|
|
$entityStore, |
83
|
|
|
$summaryFormatter, |
84
|
|
|
$logger, |
85
|
|
|
$editEntityFactory |
86
|
|
|
); |
87
|
|
|
$this->siteLookup = $siteLookup; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Get a SiteLink for a specific item and site |
92
|
|
|
* |
93
|
|
|
* @param Item $item |
94
|
|
|
* @param string $globalId |
95
|
|
|
* |
96
|
|
|
* @return SiteLink|null |
97
|
|
|
*/ |
98
|
|
|
private function getSiteLink( Item $item, $globalId ) { |
99
|
|
|
try { |
100
|
|
|
return $item->getSiteLinkList()->getBySiteId( $globalId ); |
101
|
|
|
} catch ( OutOfBoundsException $e ) { |
102
|
|
|
return null; |
103
|
|
|
} |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Get a Summary object for the edit |
108
|
|
|
* |
109
|
|
|
* @return Summary |
110
|
|
|
*/ |
111
|
|
|
public function getSummary() { |
112
|
|
|
$params = $this->getParams(); |
113
|
|
|
$siteId = $params['siteId']; |
114
|
|
|
$oldPage = $params['oldTitle']; |
115
|
|
|
$newPage = $params['newTitle']; |
116
|
|
|
|
117
|
|
|
return new Summary( |
118
|
|
|
'clientsitelink', |
119
|
|
|
'update', |
120
|
|
|
$siteId, |
121
|
|
|
[ |
122
|
|
|
$siteId . ":$oldPage", |
123
|
|
|
$siteId . ":$newPage", |
124
|
|
|
] |
125
|
|
|
); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* @return string|bool False in case the normalization failed |
130
|
|
|
*/ |
131
|
|
|
private function getNormalizedPageName() { |
132
|
|
|
if ( $this->normalizedPageName === null ) { |
133
|
|
|
$params = $this->getParams(); |
134
|
|
|
$newPage = $params['newTitle']; |
135
|
|
|
$siteId = $params['siteId']; |
136
|
|
|
|
137
|
|
|
$site = $this->siteLookup->getSite( $siteId ); |
138
|
|
|
$this->normalizedPageName = $site->normalizePageName( $newPage ); |
139
|
|
|
|
140
|
|
|
if ( $this->normalizedPageName === false ) { |
141
|
|
|
$this->logger->debug( |
142
|
|
|
'OnMove: Normalizing the page name {newPage} on {siteId} failed', |
143
|
|
|
[ |
144
|
|
|
'newPage' => $newPage, |
145
|
|
|
'siteId' => $siteId, |
146
|
|
|
] |
147
|
|
|
); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return $this->normalizedPageName; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Whether the propagated update is valid (and thus should be applied) |
157
|
|
|
* |
158
|
|
|
* @param Item $item |
159
|
|
|
* |
160
|
|
|
* @return bool |
161
|
|
|
*/ |
162
|
|
|
protected function verifyValid( Item $item ) { |
163
|
|
|
$params = $this->getParams(); |
164
|
|
|
$siteId = $params['siteId']; |
165
|
|
|
$oldPage = $params['oldTitle']; |
166
|
|
|
|
167
|
|
|
$oldSiteLink = $this->getSiteLink( $item, $siteId ); |
168
|
|
|
if ( !$oldSiteLink || $oldSiteLink->getPageName() !== $oldPage ) { |
169
|
|
|
// Probably something changed since the job has been inserted |
170
|
|
|
$this->logger->debug( |
171
|
|
|
'OnMove: The site link to {siteId} is no longer {oldPage}', |
172
|
|
|
[ |
173
|
|
|
'siteId' => $siteId, |
174
|
|
|
'oldPage' => $oldPage, |
175
|
|
|
] |
176
|
|
|
); |
177
|
|
|
return false; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
// Normalize the name, just in case the page has been updated in the mean time |
181
|
|
|
if ( $this->getNormalizedPageName() === false ) { |
182
|
|
|
return false; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
return true; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* @inheritDoc |
190
|
|
|
*/ |
191
|
|
|
protected function applyChanges( Item $item ) { |
192
|
|
|
$params = $this->getParams(); |
193
|
|
|
$siteId = $params['siteId']; |
194
|
|
|
$oldSiteLink = $this->getSiteLink( $item, $siteId ); |
195
|
|
|
|
196
|
|
|
$siteLink = new SiteLink( |
197
|
|
|
$siteId, |
198
|
|
|
$this->getNormalizedPageName(), |
|
|
|
|
199
|
|
|
$oldSiteLink->getBadges() // Keep badges |
200
|
|
|
); |
201
|
|
|
|
202
|
|
|
$item->getSiteLinkList()->removeLinkWithSiteId( $siteId ); |
203
|
|
|
$item->getSiteLinkList()->addSiteLink( $siteLink ); |
204
|
|
|
|
205
|
|
|
return true; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
} |
209
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.