31345af3fbf14f1f700edea1231033428c560d01
[lhc/web/wiklou.git] / includes / content / Content.php
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 /**
30 * Base interface for content objects.
31 *
32 * @ingroup Content
33 */
34 interface Content {
35
36 /**
37 * @since 1.21
38 *
39 * @return string A string representing the content in a way useful for
40 * building a full text search index. If no useful representation exists,
41 * this method returns an empty string.
42 *
43 * @todo: test that this actually works
44 * @todo: make sure this also works with LuceneSearch / WikiSearch
45 */
46 public function getTextForSearchIndex();
47
48 /**
49 * @since 1.21
50 *
51 * @return string|false The wikitext to include when another page includes this
52 * content, or false if the content is not includable in a wikitext page.
53 *
54 * @todo allow native handling, bypassing wikitext representation, like
55 * for includable special pages.
56 * @todo allow transclusion into other content models than Wikitext!
57 * @todo used in WikiPage and MessageCache to get message text. Not so
58 * nice. What should we use instead?!
59 */
60 public function getWikitextForTransclusion();
61
62 /**
63 * Returns a textual representation of the content suitable for use in edit
64 * summaries and log messages.
65 *
66 * @since 1.21
67 *
68 * @param $maxLength int Maximum length of the summary text
69 * @return string The summary text
70 */
71 public function getTextForSummary( $maxLength = 250 );
72
73 /**
74 * Returns native representation of the data. Interpretation depends on
75 * the data model used, as given by getDataModel().
76 *
77 * @since 1.21
78 *
79 * @return mixed The native representation of the content. Could be a
80 * string, a nested array structure, an object, a binary blob...
81 * anything, really.
82 *
83 * @note Caller must be aware of content model!
84 */
85 public function getNativeData();
86
87 /**
88 * Returns the content's nominal size in bogo-bytes.
89 *
90 * @return int
91 */
92 public function getSize();
93
94 /**
95 * Returns the ID of the content model used by this Content object.
96 * Corresponds to the CONTENT_MODEL_XXX constants.
97 *
98 * @since 1.21
99 *
100 * @return String The model id
101 */
102 public function getModel();
103
104 /**
105 * Convenience method that returns the ContentHandler singleton for handling
106 * the content model that this Content object uses.
107 *
108 * Shorthand for ContentHandler::getForContent( $this )
109 *
110 * @since 1.21
111 *
112 * @return ContentHandler
113 */
114 public function getContentHandler();
115
116 /**
117 * Convenience method that returns the default serialization format for the
118 * content model that this Content object uses.
119 *
120 * Shorthand for $this->getContentHandler()->getDefaultFormat()
121 *
122 * @since 1.21
123 *
124 * @return String
125 */
126 public function getDefaultFormat();
127
128 /**
129 * Convenience method that returns the list of serialization formats
130 * supported for the content model that this Content object uses.
131 *
132 * Shorthand for $this->getContentHandler()->getSupportedFormats()
133 *
134 * @since 1.21
135 *
136 * @return Array of supported serialization formats
137 */
138 public function getSupportedFormats();
139
140 /**
141 * Returns true if $format is a supported serialization format for this
142 * Content object, false if it isn't.
143 *
144 * Note that this should always return true if $format is null, because null
145 * stands for the default serialization.
146 *
147 * Shorthand for $this->getContentHandler()->isSupportedFormat( $format )
148 *
149 * @since 1.21
150 *
151 * @param $format string The format to check
152 * @return bool Whether the format is supported
153 */
154 public function isSupportedFormat( $format );
155
156 /**
157 * Convenience method for serializing this Content object.
158 *
159 * Shorthand for $this->getContentHandler()->serializeContent( $this, $format )
160 *
161 * @since 1.21
162 *
163 * @param $format null|string The desired serialization format (or null for
164 * the default format).
165 * @return string Serialized form of this Content object
166 */
167 public function serialize( $format = null );
168
169 /**
170 * Returns true if this Content object represents empty content.
171 *
172 * @since 1.21
173 *
174 * @return bool Whether this Content object is empty
175 */
176 public function isEmpty();
177
178 /**
179 * Returns whether the content is valid. This is intended for local validity
180 * checks, not considering global consistency.
181 *
182 * Content needs to be valid before it can be saved.
183 *
184 * This default implementation always returns true.
185 *
186 * @since 1.21
187 *
188 * @return boolean
189 */
190 public function isValid();
191
192 /**
193 * Returns true if this Content objects is conceptually equivalent to the
194 * given Content object.
195 *
196 * Contract:
197 *
198 * - Will return false if $that is null.
199 * - Will return true if $that === $this.
200 * - Will return false if $that->getModel() != $this->getModel().
201 * - Will return false if $that->getNativeData() is not equal to $this->getNativeData(),
202 * where the meaning of "equal" depends on the actual data model.
203 *
204 * Implementations should be careful to make equals() transitive and reflexive:
205 *
206 * - $a->equals( $b ) <=> $b->equals( $a )
207 * - $a->equals( $b ) && $b->equals( $c ) ==> $a->equals( $c )
208 *
209 * @since 1.21
210 *
211 * @param $that Content The Content object to compare to
212 * @return bool True if this Content object is equal to $that, false otherwise.
213 */
214 public function equals( Content $that = null );
215
216 /**
217 * Return a copy of this Content object. The following must be true for the
218 * object returned:
219 *
220 * if $copy = $original->copy()
221 *
222 * - get_class($original) === get_class($copy)
223 * - $original->getModel() === $copy->getModel()
224 * - $original->equals( $copy )
225 *
226 * If and only if the Content object is immutable, the copy() method can and
227 * should return $this. That is, $copy === $original may be true, but only
228 * for immutable content objects.
229 *
230 * @since 1.21
231 *
232 * @return Content. A copy of this object
233 */
234 public function copy( );
235
236 /**
237 * Returns true if this content is countable as a "real" wiki page, provided
238 * that it's also in a countable location (e.g. a current revision in the
239 * main namespace).
240 *
241 * @since 1.21
242 *
243 * @param $hasLinks Bool: If it is known whether this content contains
244 * links, provide this information here, to avoid redundant parsing to
245 * find out.
246 * @return boolean
247 */
248 public function isCountable( $hasLinks = null );
249
250 /**
251 * Parse the Content object and generate a ParserOutput from the result.
252 * $result->getText() can be used to obtain the generated HTML. If no HTML
253 * is needed, $generateHtml can be set to false; in that case,
254 * $result->getText() may return null.
255 *
256 * @param $title Title The page title to use as a context for rendering
257 * @param $revId null|int The revision being rendered (optional)
258 * @param $options null|ParserOptions Any parser options
259 * @param $generateHtml Boolean Whether to generate HTML (default: true). If false,
260 * the result of calling getText() on the ParserOutput object returned by
261 * this method is undefined.
262 *
263 * @since 1.21
264 *
265 * @return ParserOutput
266 */
267 public function getParserOutput( Title $title,
268 $revId = null,
269 ParserOptions $options = null, $generateHtml = true );
270 // TODO: make RenderOutput and RenderOptions base classes
271
272 /**
273 * Returns a list of DataUpdate objects for recording information about this
274 * Content in some secondary data store. If the optional second argument,
275 * $old, is given, the updates may model only the changes that need to be
276 * made to replace information about the old content with information about
277 * the new content.
278 *
279 * This default implementation calls
280 * $this->getParserOutput( $content, $title, null, null, false ),
281 * and then calls getSecondaryDataUpdates( $title, $recursive ) on the
282 * resulting ParserOutput object.
283 *
284 * Subclasses may implement this to determine the necessary updates more
285 * efficiently, or make use of information about the old content.
286 *
287 * @param $title Title The context for determining the necessary updates
288 * @param $old Content|null An optional Content object representing the
289 * previous content, i.e. the content being replaced by this Content
290 * object.
291 * @param $recursive boolean Whether to include recursive updates (default:
292 * false).
293 * @param $parserOutput ParserOutput|null Optional ParserOutput object.
294 * Provide if you have one handy, to avoid re-parsing of the content.
295 *
296 * @return Array. A list of DataUpdate objects for putting information
297 * about this content object somewhere.
298 *
299 * @since 1.21
300 */
301 public function getSecondaryDataUpdates( Title $title,
302 Content $old = null,
303 $recursive = true, ParserOutput $parserOutput = null
304 );
305
306 /**
307 * Construct the redirect destination from this content and return an
308 * array of Titles, or null if this content doesn't represent a redirect.
309 * The last element in the array is the final destination after all redirects
310 * have been resolved (up to $wgMaxRedirects times).
311 *
312 * @since 1.21
313 *
314 * @return Array of Titles, with the destination last
315 */
316 public function getRedirectChain();
317
318 /**
319 * Construct the redirect destination from this content and return a Title,
320 * or null if this content doesn't represent a redirect.
321 * This will only return the immediate redirect target, useful for
322 * the redirect table and other checks that don't need full recursion.
323 *
324 * @since 1.21
325 *
326 * @return Title: The corresponding Title
327 */
328 public function getRedirectTarget();
329
330 /**
331 * Construct the redirect destination from this content and return the
332 * Title, or null if this content doesn't represent a redirect.
333 *
334 * This will recurse down $wgMaxRedirects times or until a non-redirect
335 * target is hit in order to provide (hopefully) the Title of the final
336 * destination instead of another redirect.
337 *
338 * There is usually no need to override the default behaviour, subclasses that
339 * want to implement redirects should override getRedirectTarget().
340 *
341 * @since 1.21
342 *
343 * @return Title
344 */
345 public function getUltimateRedirectTarget();
346
347 /**
348 * Returns whether this Content represents a redirect.
349 * Shorthand for getRedirectTarget() !== null.
350 *
351 * @since 1.21
352 *
353 * @return bool
354 */
355 public function isRedirect();
356
357 /**
358 * If this Content object is a redirect, this method updates the redirect target.
359 * Otherwise, it does nothing.
360 *
361 * @since 1.21
362 *
363 * @param Title $target the new redirect target
364 *
365 * @return Content a new Content object with the updated redirect (or $this if this Content object isn't a redirect)
366 */
367 public function updateRedirect( Title $target );
368
369 /**
370 * Returns the section with the given ID.
371 *
372 * @since 1.21
373 *
374 * @param $sectionId string The section's ID, given as a numeric string.
375 * The ID "0" retrieves the section before the first heading, "1" the
376 * text between the first heading (included) and the second heading
377 * (excluded), etc.
378 * @return Content|Boolean|null The section, or false if no such section
379 * exist, or null if sections are not supported.
380 */
381 public function getSection( $sectionId );
382
383 /**
384 * Replaces a section of the content and returns a Content object with the
385 * section replaced.
386 *
387 * @since 1.21
388 *
389 * @param $section null/false or a section number (0, 1, 2, T1, T2...), or "new"
390 * @param $with Content: new content of the section
391 * @param $sectionTitle String: new section's subject, only if $section is 'new'
392 * @return string Complete article text, or null if error
393 */
394 public function replaceSection( $section, Content $with, $sectionTitle = '' );
395
396 /**
397 * Returns a Content object with pre-save transformations applied (or this
398 * object if no transformations apply).
399 *
400 * @since 1.21
401 *
402 * @param $title Title
403 * @param $user User
404 * @param $parserOptions null|ParserOptions
405 * @return Content
406 */
407 public function preSaveTransform( Title $title, User $user, ParserOptions $parserOptions );
408
409 /**
410 * Returns a new WikitextContent object with the given section heading
411 * prepended, if supported. The default implementation just returns this
412 * Content object unmodified, ignoring the section header.
413 *
414 * @since 1.21
415 *
416 * @param $header string
417 * @return Content
418 */
419 public function addSectionHeader( $header );
420
421 /**
422 * Returns a Content object with preload transformations applied (or this
423 * object if no transformations apply).
424 *
425 * @since 1.21
426 *
427 * @param $title Title
428 * @param $parserOptions null|ParserOptions
429 * @return Content
430 */
431 public function preloadTransform( Title $title, ParserOptions $parserOptions );
432
433 /**
434 * Prepare Content for saving. Called before Content is saved by WikiPage::doEditContent() and in
435 * similar places.
436 *
437 * This may be used to check the content's consistency with global state. This function should
438 * NOT write any information to the database.
439 *
440 * Note that this method will usually be called inside the same transaction bracket that will be used
441 * to save the new revision.
442 *
443 * Note that this method is called before any update to the page table is performed. This means that
444 * $page may not yet know a page ID.
445 *
446 * @since 1.21
447 *
448 * @param WikiPage $page The page to be saved.
449 * @param int $flags bitfield for use with EDIT_XXX constants, see WikiPage::doEditContent()
450 * @param int $baseRevId the ID of the current revision
451 * @param User $user
452 *
453 * @return Status A status object indicating whether the content was successfully prepared for saving.
454 * If the returned status indicates an error, a rollback will be performed and the
455 * transaction aborted.
456 *
457 * @see see WikiPage::doEditContent()
458 */
459 public function prepareSave( WikiPage $page, $flags, $baseRevId, User $user );
460
461 /**
462 * Returns a list of updates to perform when this content is deleted.
463 * The necessary updates may be taken from the Content object, or depend on
464 * the current state of the database.
465 *
466 * @since 1.21
467 *
468 * @param $page WikiPage the deleted page
469 * @param $parserOutput null|ParserOutput optional parser output object
470 * for efficient access to meta-information about the content object.
471 * Provide if you have one handy.
472 *
473 * @return array A list of DataUpdate instances that will clean up the
474 * database after deletion.
475 */
476 public function getDeletionUpdates( WikiPage $page,
477 ParserOutput $parserOutput = null );
478
479 /**
480 * Returns true if this Content object matches the given magic word.
481 *
482 * @since 1.21
483 *
484 * @param MagicWord $word the magic word to match
485 *
486 * @return bool whether this Content object matches the given magic word.
487 */
488 public function matchMagicWord( MagicWord $word );
489
490 /**
491 * Converts this content object into another content object with the given content model,
492 * if that is possible.
493 *
494 * @param String $toModel the desired content model, use the CONTENT_MODEL_XXX flags.
495 * @param String $lossy flag, set to "lossy" to allow lossy conversion. If lossy conversion is
496 * not allowed, full round-trip conversion is expected to work without losing information.
497 *
498 * @return Content|bool A content object with the content model $toModel, or false if
499 * that conversion is not supported.
500 */
501 public function convert( $toModel, $lossy = '' );
502
503 // TODO: ImagePage and CategoryPage interfere with per-content action handlers
504 // TODO: nice&sane integration of GeSHi syntax highlighting
505 // [11:59] <vvv> Hooks are ugly; make CodeHighlighter interface and a
506 // config to set the class which handles syntax highlighting
507 // [12:00] <vvv> And default it to a DummyHighlighter
508 }