Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractContent
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 23
992
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getModel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 checkModelID
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getContentHandler
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContentHandlerFactory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSupportedFormats
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isSupportedFormat
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 checkFormat
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 serialize
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getNativeData
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 isEmpty
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isValid
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 equals
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 equalsInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRedirectTarget
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isRedirect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 updateRedirect
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 replaceSection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 addSectionHeader
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 matchMagicWord
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 convert
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 * @author Daniel Kinzler
20 */
21
22namespace MediaWiki\Content;
23
24use LogicException;
25use MediaWiki\Exception\MWException;
26use MediaWiki\HookContainer\HookRunner;
27use MediaWiki\MediaWikiServices;
28use MediaWiki\Parser\MagicWord;
29use MediaWiki\Title\Title;
30
31/**
32 * Base class for all Content objects. Refer to Content for more information.
33 *
34 * @stable to extend
35 * @since 1.21
36 * @ingroup Content
37 */
38abstract class AbstractContent implements Content {
39    /**
40     * @var string
41     * @since 1.21
42     */
43    protected $model_id;
44
45    /**
46     * @stable to call
47     * @since 1.21
48     * @param string|null $modelId One of the CONTENT_MODEL_XXX constants.
49     */
50    public function __construct( $modelId = null ) {
51        $this->model_id = $modelId;
52    }
53
54    /**
55     * @see Content::getModel
56     * @since 1.21
57     * @return string
58     */
59    public function getModel() {
60        return $this->model_id;
61    }
62
63    /**
64     * Helper for subclasses
65     *
66     * @since 1.21
67     * @param string $modelId The model to check
68     * @throws MWException If the provided model ID differs from this Content object
69     */
70    protected function checkModelID( $modelId ) {
71        if ( $modelId !== $this->model_id ) {
72            throw new MWException(
73                "Bad content model: expected {$this->model_id} but got $modelId."
74            );
75        }
76    }
77
78    /**
79     * @see Content::getContentHandler
80     * @since 1.21
81     * @return ContentHandler
82     */
83    public function getContentHandler() {
84        return $this->getContentHandlerFactory()->getContentHandler( $this->getModel() );
85    }
86
87    protected function getContentHandlerFactory(): IContentHandlerFactory {
88        return MediaWikiServices::getInstance()->getContentHandlerFactory();
89    }
90
91    /**
92     * @see Content::getDefaultFormat
93     * @since 1.21
94     * @return string
95     */
96    public function getDefaultFormat() {
97        return $this->getContentHandler()->getDefaultFormat();
98    }
99
100    /**
101     * @see Content::getSupportedFormats
102     * @since 1.21
103     * @return string[]
104     */
105    public function getSupportedFormats() {
106        return $this->getContentHandler()->getSupportedFormats();
107    }
108
109    /**
110     * @see Content::isSupportedFormat
111     * @since 1.21
112     * @param string $format
113     * @return bool
114     */
115    public function isSupportedFormat( $format ) {
116        if ( !$format ) {
117            return true; // this means "use the default"
118        }
119
120        return $this->getContentHandler()->isSupportedFormat( $format );
121    }
122
123    /**
124     * Helper for subclasses.
125     *
126     * @since 1.21
127     * @param string $format The serialization format to check.
128     * @throws MWException If the format is not supported by this Content object
129     */
130    protected function checkFormat( $format ) {
131        if ( !$this->isSupportedFormat( $format ) ) {
132            throw new MWException(
133                "Format $format is not supported for content model " .
134                $this->getModel()
135            );
136        }
137    }
138
139    /**
140     * @stable to override
141     * @see Content::serialize
142     * @since 1.21
143     * @param string|null $format
144     * @return string
145     */
146    public function serialize( $format = null ) {
147        return $this->getContentHandler()->serializeContent( $this, $format );
148    }
149
150    /**
151     * @see Content::getNativeData
152     * @stable to override
153     * @deprecated since 1.33 Use TextContent::getText() instead.
154     *  For other content models, use specialized getters.
155     * @since 1.21
156     * @return mixed
157     */
158    public function getNativeData() {
159        wfDeprecated( __METHOD__, '1.33' );
160        throw new LogicException( __METHOD__ . ': not implemented' );
161    }
162
163    /**
164     * @see Content::isEmpty
165     * @stable to override
166     * @since 1.21
167     * @return bool
168     */
169    public function isEmpty() {
170        return $this->getSize() === 0;
171    }
172
173    /**
174     * @see Content::isValid
175     * @stable to override
176     * @since 1.21
177     * @return bool
178     */
179    public function isValid() {
180        return true;
181    }
182
183    /**
184     * @see Content::equals
185     * @stable to override
186     * @since 1.21
187     * @param Content|null $that
188     * @return bool
189     */
190    public function equals( ?Content $that = null ) {
191        if ( $that === null ) {
192            return false;
193        }
194
195        if ( $that === $this ) {
196            return true;
197        }
198
199        if ( $that->getModel() !== $this->getModel() ) {
200            return false;
201        }
202
203        // For type safety. Needed for odd cases like non-TextContents using CONTENT_MODEL_WIKITEXT
204        if ( get_class( $that ) !== get_class( $this ) ) {
205            return false;
206        }
207
208        return $this->equalsInternal( $that );
209    }
210
211    /**
212     * Helper for AbstractContent::equals.
213     *
214     * @note Do not call this method directly, call Content::equals() instead.
215     *
216     * This method can be overwritten by subclasses that only need to implement custom
217     * equality checks, with the rest of the Content::equals contract taken care of by
218     * AbstractContent::equals.
219     *
220     * This default implementation compares Content::serialize of each object.
221     *
222     * If you override this method, you can safely assume that $that is an instance of the same
223     * class as the current Content object. This is ensured by AbstractContent::equals.
224     *
225     * @see Content::equals
226     * @stable to override
227     * @param Content $that
228     * @return bool
229     */
230    protected function equalsInternal( Content $that ) {
231        return $this->serialize() === $that->serialize();
232    }
233
234    /**
235     * Subclasses that implement redirects should override this.
236     *
237     * @see Content::getRedirectTarget
238     * @stable to override
239     * @since 1.21
240     * @return Title|null
241     */
242    public function getRedirectTarget() {
243        return null;
244    }
245
246    /**
247     * @see Content::isRedirect
248     * @since 1.21
249     * @return bool
250     */
251    public function isRedirect() {
252        return $this->getRedirectTarget() !== null;
253    }
254
255    /**
256     * This default implementation always returns $this.
257     * Subclasses that implement redirects should override this.
258     *
259     * @stable to override
260     * @see Content::updateRedirect
261     * @since 1.21
262     * @param Title $target
263     * @return Content $this
264     *
265     */
266    public function updateRedirect( Title $target ) {
267        return $this;
268    }
269
270    /**
271     * @stable to override
272     * @see Content::getSection
273     * @since 1.21
274     * @param string|int $sectionId
275     * @return null
276     */
277    public function getSection( $sectionId ) {
278        return null;
279    }
280
281    /**
282     * @stable to override
283     * @see Content::replaceSection
284     * @since 1.21
285     * @param string|int|null|false $sectionId
286     * @param Content $with
287     * @param string $sectionTitle
288     * @return null
289     *
290     */
291    public function replaceSection( $sectionId, Content $with, $sectionTitle = '' ) {
292        return null;
293    }
294
295    /**
296     * @stable to override
297     * @see Content::addSectionHeader
298     * @since 1.21
299     * @param string $header
300     * @return Content $this
301     */
302    public function addSectionHeader( $header ) {
303        return $this;
304    }
305
306    /**
307     * This default implementation always returns false. Subclasses may override
308     * this to supply matching logic.
309     *
310     * @stable to override
311     * @see Content::matchMagicWord
312     * @since 1.21
313     * @param MagicWord $word
314     * @return bool
315     */
316    public function matchMagicWord( MagicWord $word ) {
317        return false;
318    }
319
320    /**
321     * This base implementation calls the hook ConvertContent to enable custom conversions.
322     * Subclasses may override this to implement conversion for "their" content model.
323     *
324     * @stable to override
325     * @see Content::convert()
326     * @param string $toModel
327     * @param string $lossy
328     * @return Content|false
329     */
330    public function convert( $toModel, $lossy = '' ) {
331        if ( $this->getModel() === $toModel ) {
332            // nothing to do, shorten out.
333            return $this;
334        }
335
336        $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
337        $result = false;
338
339        ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
340            ->onConvertContent( $this, $toModel, $lossy, $result );
341
342        return $result;
343    }
344
345}
346
347/** @deprecated class alias since 1.43 */
348class_alias( AbstractContent::class, 'AbstractContent' );