Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
82.00% |
41 / 50 |
|
75.00% |
9 / 12 |
CRAP | |
0.00% |
0 / 1 |
CognatePageHookHandler | |
82.00% |
41 / 50 |
|
75.00% |
9 / 12 |
26.09 | |
0.00% |
0 / 1 |
__construct | |
75.00% |
9 / 12 |
|
0.00% |
0 / 1 |
1.02 | |||
overrideRevisionNewFromId | |
40.00% |
2 / 5 |
|
0.00% |
0 / 1 |
2.86 | |||
overridePreviousRevision | |
40.00% |
2 / 5 |
|
0.00% |
0 / 1 |
2.86 | |||
onPageContentSaveComplete | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
onWikiPageDeletionUpdates | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
newDeferrableDelete | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
onArticleUndelete | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
newRevisionRecordFromId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
onTitleMoveComplete | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
isActionableTarget | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
getRepo | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
onContentChange | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace Cognate\HookHandler; |
4 | |
5 | use BadMethodCallException; |
6 | use Cognate\CognateRepo; |
7 | use Cognate\CognateServices; |
8 | use MediaWiki\Deferred\DeferrableUpdate; |
9 | use MediaWiki\Deferred\MWCallableUpdate; |
10 | use MediaWiki\Linker\LinkTarget; |
11 | use MediaWiki\MediaWikiServices; |
12 | use MediaWiki\Revision\RevisionRecord; |
13 | use MediaWiki\Title\Title; |
14 | |
15 | /** |
16 | * @license GPL-2.0-or-later |
17 | * @author Addshore |
18 | */ |
19 | class CognatePageHookHandler { |
20 | |
21 | /** |
22 | * @var string |
23 | */ |
24 | private $dbName; |
25 | |
26 | /** |
27 | * @var int[] |
28 | */ |
29 | private $namespaces; |
30 | |
31 | /** |
32 | * @var callable |
33 | */ |
34 | private $newRevisionFromIdCallable; |
35 | |
36 | /** |
37 | * @var callable |
38 | */ |
39 | private $previousRevisionCallable; |
40 | |
41 | /** |
42 | * @param int[] $namespaces array of namespace ids the hooks should operate on |
43 | * @param string $dbName The dbName of the current site |
44 | */ |
45 | public function __construct( array $namespaces, $dbName ) { |
46 | $this->namespaces = $namespaces; |
47 | $this->dbName = $dbName; |
48 | $this->newRevisionFromIdCallable = static function ( $id ) { |
49 | return MediaWikiServices::getInstance() |
50 | ->getRevisionLookup() |
51 | ->getRevisionById( $id ); |
52 | }; |
53 | $this->previousRevisionCallable = static function ( $revRecord ) { |
54 | return MediaWikiServices::getInstance() |
55 | ->getRevisionLookup() |
56 | ->getPreviousRevision( $revRecord ); |
57 | }; |
58 | } |
59 | |
60 | /** |
61 | * Overrides the use of RevisionLookup::getRevisionById in this class |
62 | * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined. |
63 | * |
64 | * @param callable $callback |
65 | */ |
66 | public function overrideRevisionNewFromId( callable $callback ) { |
67 | if ( !defined( 'MW_PHPUNIT_TEST' ) ) { |
68 | throw new BadMethodCallException( |
69 | 'Cannot override RevisionLookup::getRevisionById callback in operation.' |
70 | ); |
71 | } |
72 | $this->newRevisionFromIdCallable = $callback; |
73 | } |
74 | |
75 | /** |
76 | * Overrides the use of RevisionLookup::getPreviousRevision in this class |
77 | * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined. |
78 | * |
79 | * @param callable $callback |
80 | */ |
81 | public function overridePreviousRevision( callable $callback ) { |
82 | if ( !defined( 'MW_PHPUNIT_TEST' ) ) { |
83 | throw new BadMethodCallException( |
84 | 'Cannot override RevisionLookup::getPreviousRevision callback in operation.' |
85 | ); |
86 | } |
87 | $this->previousRevisionCallable = $callback; |
88 | } |
89 | |
90 | /** |
91 | * Occurs after the save page request has been processed. |
92 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/PageContentSaveComplete |
93 | * |
94 | * @note for mediawiki 1.35+, this is run for the PageSaveComplete hook instead of the |
95 | * PageContentSaveComplete hook |
96 | * |
97 | * @param LinkTarget $title |
98 | * @param RevisionRecord|null $revisionRecord |
99 | */ |
100 | public function onPageContentSaveComplete( |
101 | LinkTarget $title, |
102 | ?RevisionRecord $revisionRecord = null |
103 | ) { |
104 | // A null revision means a null edit / no-op edit was made, no need to process that. |
105 | if ( $revisionRecord === null ) { |
106 | return; |
107 | } |
108 | |
109 | if ( !$this->isActionableTarget( $title ) ) { |
110 | return; |
111 | } |
112 | |
113 | $this->onContentChange( $title ); |
114 | } |
115 | |
116 | /** |
117 | * Manipulate the list of DataUpdates to be applied when a page is deleted |
118 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/WikiPageDeletionUpdates |
119 | * |
120 | * @param LinkTarget $title |
121 | * @param DeferrableUpdate[] &$updates |
122 | */ |
123 | public function onWikiPageDeletionUpdates( |
124 | LinkTarget $title, |
125 | array &$updates |
126 | ) { |
127 | if ( $this->isActionableTarget( $title ) ) { |
128 | $updates[] = $this->newDeferrableDelete( $title, $this->dbName ); |
129 | } |
130 | } |
131 | |
132 | /** |
133 | * @param LinkTarget $linkTarget |
134 | * @param string $dbName |
135 | * |
136 | * @return MWCallableUpdate |
137 | */ |
138 | private function newDeferrableDelete( LinkTarget $linkTarget, $dbName ) { |
139 | return new MWCallableUpdate( |
140 | function () use ( $dbName, $linkTarget ) { |
141 | $this->getRepo()->deletePage( $dbName, $linkTarget ); |
142 | }, |
143 | __METHOD__ |
144 | ); |
145 | } |
146 | |
147 | /** |
148 | * When one or more revisions of an article are restored |
149 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/ArticleUndelete |
150 | * |
151 | * @param Title $title |
152 | */ |
153 | public function onArticleUndelete( |
154 | Title $title |
155 | ) { |
156 | $revision = $this->newRevisionRecordFromId( $title->getLatestRevID() ); |
157 | if ( !$this->isActionableTarget( $title ) || $revision == null ) { |
158 | return; |
159 | } |
160 | |
161 | $this->onContentChange( $title ); |
162 | } |
163 | |
164 | /** |
165 | * @param int $id |
166 | * |
167 | * @return null|RevisionRecord |
168 | */ |
169 | private function newRevisionRecordFromId( $id ) { |
170 | return call_user_func( $this->newRevisionFromIdCallable, $id ); |
171 | } |
172 | |
173 | /** |
174 | * Occurs whenever a request to move an article is completed, after the database transaction |
175 | * commits. |
176 | * |
177 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/TitleMoveComplete |
178 | * |
179 | * @note for mediawiki 1.35+, this is run for the PageMoveComplete hook instead of the |
180 | * TitleMoveComplete hook |
181 | * |
182 | * @param LinkTarget $title |
183 | * @param LinkTarget $newTitle |
184 | */ |
185 | public function onTitleMoveComplete( |
186 | LinkTarget $title, |
187 | LinkTarget $newTitle |
188 | ) { |
189 | $repo = $this->getRepo(); |
190 | if ( $this->isActionableTarget( $title ) ) { |
191 | $repo->deletePage( $this->dbName, $title ); |
192 | } |
193 | if ( $this->isActionableTarget( $newTitle ) ) { |
194 | $repo->savePage( $this->dbName, $newTitle ); |
195 | } |
196 | } |
197 | |
198 | /** |
199 | * Actionable targets have a namespace id that is: |
200 | * - One of the default MediaWiki (between NS_MAIN and NS_CATEGORY_TALK |
201 | * - Defined as a namespace to record in the configuration |
202 | * @param LinkTarget $linkTarget |
203 | * @return bool |
204 | */ |
205 | private function isActionableTarget( LinkTarget $linkTarget ) { |
206 | $namespace = $linkTarget->getNamespace(); |
207 | return in_array( $namespace, $this->namespaces ) && |
208 | $namespace >= NS_MAIN && $namespace <= NS_CATEGORY_TALK; |
209 | } |
210 | |
211 | /** |
212 | * @return CognateRepo |
213 | */ |
214 | private function getRepo() { |
215 | return CognateServices::getRepo(); |
216 | } |
217 | |
218 | /** |
219 | * @param LinkTarget $linkTarget |
220 | */ |
221 | private function onContentChange( LinkTarget $linkTarget ) { |
222 | $this->getRepo()->savePage( $this->dbName, $linkTarget ); |
223 | } |
224 | |
225 | } |