Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 50 |
|
0.00% |
0 / 23 |
CRAP | |
0.00% |
0 / 1 |
AbstractContent | |
0.00% |
0 / 49 |
|
0.00% |
0 / 23 |
992 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getModel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
checkModelID | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getContentHandler | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getContentHandlerFactory | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDefaultFormat | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSupportedFormats | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isSupportedFormat | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
checkFormat | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
serialize | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getNativeData | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
isEmpty | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isValid | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
equals | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
equalsInternal | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getRedirectTarget | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isRedirect | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
updateRedirect | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
replaceSection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
addSectionHeader | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
matchMagicWord | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
convert | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * A content object represents page content, e.g. the text to show on a page. |
4 | * Content objects have no knowledge about how they relate to Wiki pages. |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License along |
17 | * with this program; if not, write to the Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
19 | * http://www.gnu.org/copyleft/gpl.html |
20 | * |
21 | * @since 1.21 |
22 | * |
23 | * @file |
24 | * @ingroup Content |
25 | * |
26 | * @author Daniel Kinzler |
27 | */ |
28 | |
29 | namespace MediaWiki\Content; |
30 | |
31 | use LogicException; |
32 | use MediaWiki\HookContainer\HookRunner; |
33 | use MediaWiki\MediaWikiServices; |
34 | use MediaWiki\Parser\MagicWord; |
35 | use MediaWiki\Title\Title; |
36 | use MWException; |
37 | |
38 | /** |
39 | * Base implementation for content objects. |
40 | * |
41 | * @stable to extend |
42 | * |
43 | * @ingroup Content |
44 | */ |
45 | abstract class AbstractContent implements Content { |
46 | /** |
47 | * Name of the content model this Content object represents. |
48 | * Use with CONTENT_MODEL_XXX constants |
49 | * |
50 | * @since 1.21 |
51 | * |
52 | * @var string |
53 | */ |
54 | protected $model_id; |
55 | |
56 | /** |
57 | * @stable to call |
58 | * |
59 | * @param string|null $modelId |
60 | * |
61 | * @since 1.21 |
62 | */ |
63 | public function __construct( $modelId = null ) { |
64 | $this->model_id = $modelId; |
65 | } |
66 | |
67 | /** |
68 | * @since 1.21 |
69 | * |
70 | * @see Content::getModel |
71 | * @return string |
72 | */ |
73 | public function getModel() { |
74 | return $this->model_id; |
75 | } |
76 | |
77 | /** |
78 | * @since 1.21 |
79 | * |
80 | * @param string $modelId The model to check |
81 | * |
82 | * @throws MWException If the provided ID is not the ID of the content model supported by this |
83 | * Content object. |
84 | */ |
85 | protected function checkModelID( $modelId ) { |
86 | if ( $modelId !== $this->model_id ) { |
87 | throw new MWException( |
88 | "Bad content model: " . |
89 | "expected {$this->model_id} " . |
90 | "but got $modelId." |
91 | ); |
92 | } |
93 | } |
94 | |
95 | /** |
96 | * @since 1.21 |
97 | * |
98 | * @see Content::getContentHandler |
99 | * @return ContentHandler |
100 | */ |
101 | public function getContentHandler() { |
102 | return $this->getContentHandlerFactory()->getContentHandler( $this->getModel() ); |
103 | } |
104 | |
105 | /** |
106 | * @return IContentHandlerFactory |
107 | */ |
108 | protected function getContentHandlerFactory(): IContentHandlerFactory { |
109 | return MediaWikiServices::getInstance()->getContentHandlerFactory(); |
110 | } |
111 | |
112 | /** |
113 | * @since 1.21 |
114 | * |
115 | * @see Content::getDefaultFormat |
116 | * @return string |
117 | */ |
118 | public function getDefaultFormat() { |
119 | return $this->getContentHandler()->getDefaultFormat(); |
120 | } |
121 | |
122 | /** |
123 | * @since 1.21 |
124 | * |
125 | * @see Content::getSupportedFormats |
126 | * @return string[] |
127 | */ |
128 | public function getSupportedFormats() { |
129 | return $this->getContentHandler()->getSupportedFormats(); |
130 | } |
131 | |
132 | /** |
133 | * @since 1.21 |
134 | * |
135 | * @param string $format |
136 | * |
137 | * @return bool |
138 | * |
139 | * @see Content::isSupportedFormat |
140 | */ |
141 | public function isSupportedFormat( $format ) { |
142 | if ( !$format ) { |
143 | return true; // this means "use the default" |
144 | } |
145 | |
146 | return $this->getContentHandler()->isSupportedFormat( $format ); |
147 | } |
148 | |
149 | /** |
150 | * @since 1.21 |
151 | * |
152 | * @param string $format The serialization format to check. |
153 | * |
154 | * @throws MWException If the format is not supported by this content handler. |
155 | */ |
156 | protected function checkFormat( $format ) { |
157 | if ( !$this->isSupportedFormat( $format ) ) { |
158 | throw new MWException( |
159 | "Format $format is not supported for content model " . |
160 | $this->getModel() |
161 | ); |
162 | } |
163 | } |
164 | |
165 | /** |
166 | * @stable to override |
167 | * @since 1.21 |
168 | * |
169 | * @param string|null $format |
170 | * |
171 | * @return string |
172 | * |
173 | * @see Content::serialize |
174 | */ |
175 | public function serialize( $format = null ) { |
176 | return $this->getContentHandler()->serializeContent( $this, $format ); |
177 | } |
178 | |
179 | /** |
180 | * Returns native representation of the data. Interpretation depends on |
181 | * the data model used, as given by getDataModel(). |
182 | * |
183 | * @stable to override |
184 | * @since 1.21 |
185 | * |
186 | * @deprecated since 1.33. Use getText() for TextContent instances. |
187 | * For other content models, use specialized getters. |
188 | * Emitting deprecation warnings since 1.41. |
189 | * |
190 | * @return mixed The native representation of the content. Could be a |
191 | * string, a nested array structure, an object, a binary blob... |
192 | * anything, really. |
193 | * @throws LogicException |
194 | * |
195 | * @note Caller must be aware of content model! |
196 | */ |
197 | public function getNativeData() { |
198 | wfDeprecated( __METHOD__, '1.33' ); |
199 | throw new LogicException( __METHOD__ . ': not implemented' ); |
200 | } |
201 | |
202 | /** |
203 | * @stable to override |
204 | * @since 1.21 |
205 | * |
206 | * @return bool |
207 | * |
208 | * @see Content::isEmpty |
209 | */ |
210 | public function isEmpty() { |
211 | return $this->getSize() === 0; |
212 | } |
213 | |
214 | /** |
215 | * Subclasses may override this to implement (light weight) validation. |
216 | * |
217 | * @stable to override |
218 | * @since 1.21 |
219 | * |
220 | * @return bool Always true. |
221 | * |
222 | * @see Content::isValid |
223 | */ |
224 | public function isValid() { |
225 | return true; |
226 | } |
227 | |
228 | /** |
229 | * Decides whether two Content objects are equal. |
230 | * Two Content objects MUST not be considered equal if they do not share the same content model. |
231 | * Two Content objects that are equal SHOULD have the same serialization. |
232 | * |
233 | * This default implementation relies on equalsInternal() to determine whether the |
234 | * Content objects are logically equivalent. Subclasses that need to implement a custom |
235 | * equality check should consider overriding equalsInternal(). Subclasses that override |
236 | * equals() itself MUST make sure that the implementation returns false for $that === null, |
237 | * and true for $that === this. It MUST also return false if $that does not have the same |
238 | * content model. |
239 | * |
240 | * @stable to override |
241 | * @since 1.21 |
242 | * |
243 | * @param Content|null $that |
244 | * |
245 | * @return bool |
246 | * |
247 | * @see Content::equals |
248 | */ |
249 | public function equals( Content $that = null ) { |
250 | if ( $that === null ) { |
251 | return false; |
252 | } |
253 | |
254 | if ( $that === $this ) { |
255 | return true; |
256 | } |
257 | |
258 | if ( $that->getModel() !== $this->getModel() ) { |
259 | return false; |
260 | } |
261 | |
262 | // For type safety. Needed for odd cases like non-TextContents using CONTENT_MODEL_WIKITEXT |
263 | if ( get_class( $that ) !== get_class( $this ) ) { |
264 | return false; |
265 | } |
266 | |
267 | return $this->equalsInternal( $that ); |
268 | } |
269 | |
270 | /** |
271 | * Checks whether $that is logically equal to this Content object. |
272 | * |
273 | * This method can be overwritten by subclasses that need to implement custom |
274 | * equality checks. |
275 | * |
276 | * This default implementation checks whether the serializations |
277 | * of $this and $that are the same: $this->serialize() === $that->serialize() |
278 | * |
279 | * Implementors can assume that $that is an instance of the same class |
280 | * as the present Content object, as long as equalsInternal() is only called |
281 | * by the standard implementation of equals(). |
282 | * |
283 | * @note Do not call this method directly, call equals() instead. |
284 | * |
285 | * @stable to override |
286 | * |
287 | * @param Content $that |
288 | * @return bool |
289 | */ |
290 | protected function equalsInternal( Content $that ) { |
291 | return $this->serialize() === $that->serialize(); |
292 | } |
293 | |
294 | /** |
295 | * Subclasses that implement redirects should override this. |
296 | * |
297 | * @stable to override |
298 | * @since 1.21 |
299 | * |
300 | * @return Title|null |
301 | * |
302 | * @see Content::getRedirectTarget |
303 | */ |
304 | public function getRedirectTarget() { |
305 | return null; |
306 | } |
307 | |
308 | /** |
309 | * @since 1.21 |
310 | * |
311 | * @return bool |
312 | * |
313 | * @see Content::isRedirect |
314 | */ |
315 | public function isRedirect() { |
316 | return $this->getRedirectTarget() !== null; |
317 | } |
318 | |
319 | /** |
320 | * This default implementation always returns $this. |
321 | * Subclasses that implement redirects should override this. |
322 | * |
323 | * @stable to override |
324 | * @since 1.21 |
325 | * |
326 | * @param Title $target |
327 | * |
328 | * @return Content $this |
329 | * |
330 | * @see Content::updateRedirect |
331 | */ |
332 | public function updateRedirect( Title $target ) { |
333 | return $this; |
334 | } |
335 | |
336 | /** |
337 | * @stable to override |
338 | * @since 1.21 |
339 | * |
340 | * @param string|int $sectionId |
341 | * @return null |
342 | * |
343 | * @see Content::getSection |
344 | */ |
345 | public function getSection( $sectionId ) { |
346 | return null; |
347 | } |
348 | |
349 | /** |
350 | * @stable to override |
351 | * @since 1.21 |
352 | * |
353 | * @param string|int|null|false $sectionId |
354 | * @param Content $with |
355 | * @param string $sectionTitle |
356 | * @return null |
357 | * |
358 | * @see Content::replaceSection |
359 | */ |
360 | public function replaceSection( $sectionId, Content $with, $sectionTitle = '' ) { |
361 | return null; |
362 | } |
363 | |
364 | /** |
365 | * @stable to override |
366 | * @since 1.21 |
367 | * |
368 | * @param string $header |
369 | * @return Content $this |
370 | * |
371 | * @see Content::addSectionHeader |
372 | */ |
373 | public function addSectionHeader( $header ) { |
374 | return $this; |
375 | } |
376 | |
377 | /** |
378 | * This default implementation always returns false. Subclasses may override |
379 | * this to supply matching logic. |
380 | * |
381 | * @stable to override |
382 | * @since 1.21 |
383 | * |
384 | * @param MagicWord $word |
385 | * |
386 | * @return bool Always false. |
387 | * |
388 | * @see Content::matchMagicWord |
389 | */ |
390 | public function matchMagicWord( MagicWord $word ) { |
391 | return false; |
392 | } |
393 | |
394 | /** |
395 | * This base implementation calls the hook ConvertContent to enable custom conversions. |
396 | * Subclasses may override this to implement conversion for "their" content model. |
397 | * |
398 | * @stable to override |
399 | * |
400 | * @param string $toModel |
401 | * @param string $lossy |
402 | * |
403 | * @return Content|false |
404 | * |
405 | * @see Content::convert() |
406 | */ |
407 | public function convert( $toModel, $lossy = '' ) { |
408 | if ( $this->getModel() === $toModel ) { |
409 | // nothing to do, shorten out. |
410 | return $this; |
411 | } |
412 | |
413 | $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience |
414 | $result = false; |
415 | |
416 | ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) ) |
417 | ->onConvertContent( $this, $toModel, $lossy, $result ); |
418 | |
419 | return $result; |
420 | } |
421 | |
422 | } |
423 | |
424 | /** @deprecated class alias since 1.43 */ |
425 | class_alias( AbstractContent::class, 'AbstractContent' ); |