MediaWiki  master
AbstractContent.php
Go to the documentation of this file.
1 <?php
34 abstract class AbstractContent implements Content {
43  protected $model_id;
44 
50  public function __construct( $modelId = null ) {
51  $this->model_id = $modelId;
52  }
53 
60  public function getModel() {
61  return $this->model_id;
62  }
63 
72  protected function checkModelID( $modelId ) {
73  if ( $modelId !== $this->model_id ) {
74  throw new MWException(
75  "Bad content model: " .
76  "expected {$this->model_id} " .
77  "but got $modelId."
78  );
79  }
80  }
81 
88  public function getContentHandler() {
89  return ContentHandler::getForContent( $this );
90  }
91 
98  public function getDefaultFormat() {
99  return $this->getContentHandler()->getDefaultFormat();
100  }
101 
108  public function getSupportedFormats() {
109  return $this->getContentHandler()->getSupportedFormats();
110  }
111 
121  public function isSupportedFormat( $format ) {
122  if ( !$format ) {
123  return true; // this means "use the default"
124  }
125 
126  return $this->getContentHandler()->isSupportedFormat( $format );
127  }
128 
136  protected function checkFormat( $format ) {
137  if ( !$this->isSupportedFormat( $format ) ) {
138  throw new MWException(
139  "Format $format is not supported for content model " .
140  $this->getModel()
141  );
142  }
143  }
144 
154  public function serialize( $format = null ) {
155  return $this->getContentHandler()->serializeContent( $this, $format );
156  }
157 
165  public function isEmpty() {
166  return $this->getSize() === 0;
167  }
168 
178  public function isValid() {
179  return true;
180  }
181 
202  public function equals( Content $that = null ) {
203  if ( is_null( $that ) ) {
204  return false;
205  }
206 
207  if ( $that === $this ) {
208  return true;
209  }
210 
211  if ( $that->getModel() !== $this->getModel() ) {
212  return false;
213  }
214 
215  // For type safety. Needed for odd cases like MessageContent using CONTENT_MODEL_WIKITEXT
216  if ( get_class( $that ) !== get_class( $this ) ) {
217  return false;
218  }
219 
220  return $this->equalsInternal( $that );
221  }
222 
241  protected function equalsInternal( Content $that ) {
242  return $this->serialize() === $that->serialize();
243  }
244 
268  public function getSecondaryDataUpdates( Title $title, Content $old = null,
269  $recursive = true, ParserOutput $parserOutput = null
270  ) {
271  if ( $parserOutput === null ) {
272  $parserOutput = $this->getParserOutput( $title, null, null, false );
273  }
274 
275  $updates = [
276  new LinksUpdate( $title, $parserOutput, $recursive )
277  ];
278 
279  Hooks::run( 'SecondaryDataUpdates', [ $title, $old, $recursive, $parserOutput, &$updates ] );
280 
281  return $updates;
282  }
283 
291  public function getRedirectChain() {
292  global $wgMaxRedirects;
293  $title = $this->getRedirectTarget();
294  if ( is_null( $title ) ) {
295  return null;
296  }
297  // recursive check to follow double redirects
298  $recurse = $wgMaxRedirects;
299  $titles = [ $title ];
300  while ( --$recurse > 0 ) {
301  if ( $title->isRedirect() ) {
302  $page = WikiPage::factory( $title );
303  $newtitle = $page->getRedirectTarget();
304  } else {
305  break;
306  }
307  // Redirects to some special pages are not permitted
308  if ( $newtitle instanceof Title && $newtitle->isValidRedirectTarget() ) {
309  // The new title passes the checks, so make that our current
310  // title so that further recursion can be checked
311  $title = $newtitle;
312  $titles[] = $newtitle;
313  } else {
314  break;
315  }
316  }
317 
318  return $titles;
319  }
320 
330  public function getRedirectTarget() {
331  return null;
332  }
333 
343  public function getUltimateRedirectTarget() {
344  $titles = $this->getRedirectChain();
345 
346  return $titles ? array_pop( $titles ) : null;
347  }
348 
356  public function isRedirect() {
357  return $this->getRedirectTarget() !== null;
358  }
359 
372  public function updateRedirect( Title $target ) {
373  return $this;
374  }
375 
384  public function getSection( $sectionId ) {
385  return null;
386  }
387 
398  public function replaceSection( $sectionId, Content $with, $sectionTitle = '' ) {
399  return null;
400  }
401 
412  public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
413  return $this;
414  }
415 
424  public function addSectionHeader( $header ) {
425  return $this;
426  }
427 
438  public function preloadTransform( Title $title, ParserOptions $popts, $params = [] ) {
439  return $this;
440  }
441 
453  public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) {
454  if ( $this->isValid() ) {
455  return Status::newGood();
456  } else {
457  return Status::newFatal( "invalid-content-data" );
458  }
459  }
460 
471  public function getDeletionUpdates( WikiPage $page, ParserOutput $parserOutput = null ) {
472  return [
473  new LinksDeletionUpdate( $page ),
474  ];
475  }
476 
489  public function matchMagicWord( MagicWord $word ) {
490  return false;
491  }
492 
504  public function convert( $toModel, $lossy = '' ) {
505  if ( $this->getModel() === $toModel ) {
506  // nothing to do, shorten out.
507  return $this;
508  }
509 
510  $lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
511  $result = false;
512 
513  Hooks::run( 'ConvertContent', [ $this, $toModel, $lossy, &$result ] );
514 
515  return $result;
516  }
517 
538  public function getParserOutput( Title $title, $revId = null,
539  ParserOptions $options = null, $generateHtml = true
540  ) {
541  if ( $options === null ) {
542  $options = ParserOptions::newCanonical( 'canonical' );
543  }
544 
545  $po = new ParserOutput();
546  $options->registerWatcher( [ $po, 'recordOption' ] );
547 
548  if ( Hooks::run( 'ContentGetParserOutput',
549  [ $this, $title, $revId, $options, $generateHtml, &$po ] )
550  ) {
551  // Save and restore the old value, just in case something is reusing
552  // the ParserOptions object in some weird way.
553  $oldRedir = $options->getRedirectTarget();
554  $options->setRedirectTarget( $this->getRedirectTarget() );
555  $this->fillParserOutput( $title, $revId, $options, $generateHtml, $po );
556  $options->setRedirectTarget( $oldRedir );
557  }
558 
559  Hooks::run( 'ContentAlterParserOutput', [ $this, $title, $po ] );
560  $options->registerWatcher( null );
561 
562  return $po;
563  }
564 
586  protected function fillParserOutput( Title $title, $revId,
587  ParserOptions $options, $generateHtml, ParserOutput &$output
588  ) {
589  // Don't make abstract, so subclasses that override getParserOutput() directly don't fail.
590  throw new MWException( 'Subclasses of AbstractContent must override fillParserOutput!' );
591  }
592 }
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:142
isValid()
Subclasses may override this to implement (light weight) validation.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:69
preSaveTransform(Title $title, User $user, ParserOptions $popts)
isSupportedFormat( $format)
$model_id
Name of the content model this Content object represents.
getDeletionUpdates(WikiPage $page, ParserOutput $parserOutput=null)
__construct( $modelId=null)
static newCanonical( $context=null, $userLang=null)
Creates a "canonical" ParserOptions object.
The User object encapsulates all of the user-specific settings (user_id, name, rights, email address, options, last login time).
Definition: User.php:51
getSize()
Returns the content&#39;s nominal size in "bogo-bytes".
equalsInternal(Content $that)
Checks whether $that is logically equal to this Content object.
preloadTransform(Title $title, ParserOptions $popts, $params=[])
getSecondaryDataUpdates(Title $title, Content $old=null, $recursive=true, ParserOutput $parserOutput=null)
Returns a list of DataUpdate objects for recording information about this Content in some secondary d...
$wgMaxRedirects
Max number of redirects to follow when resolving redirects.
updateRedirect(Title $target)
This default implementation always returns $this.
static getForContent(Content $content)
Returns the appropriate ContentHandler singleton for the given Content object.
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:81
equals(Content $that=null)
Decides whether two Content objects are equal.
Base implementation for content objects.
replaceSection( $sectionId, Content $with, $sectionTitle='')
$header
checkModelID( $modelId)
addSectionHeader( $header)
prepareSave(WikiPage $page, $flags, $parentRevId, User $user)
serialize( $format=null)
getSection( $sectionId)
fillParserOutput(Title $title, $revId, ParserOptions $options, $generateHtml, ParserOutput &$output)
Fills the provided ParserOutput with information derived from the content.
getParserOutput(Title $title, $revId=null, ParserOptions $options=null, $generateHtml=true)
Returns a ParserOutput object containing information derived from this content.
convert( $toModel, $lossy='')
This base implementation calls the hook ConvertContent to enable custom conversions.
matchMagicWord(MagicWord $word)
This default implementation always returns false.
getRedirectTarget()
Subclasses that implement redirects should override this.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
This class encapsulates "magic words" such as "#redirect", NOTOC, etc.
Definition: MagicWord.php:57
serialize( $format=null)
Convenience method for serializing this Content object.