MediaWiki REL1_34
WikitextContent.php
Go to the documentation of this file.
1<?php
30
37 private $redirectTargetAndText = null;
38
43 private $hadSignature = false;
44
49
50 public function __construct( $text ) {
51 parent::__construct( $text, CONTENT_MODEL_WIKITEXT );
52 }
53
61 public function getSection( $sectionId ) {
62 $text = $this->getText();
63 $sect = MediaWikiServices::getInstance()->getParser()
64 ->getSection( $text, $sectionId, false );
65
66 if ( $sect === false ) {
67 return false;
68 } else {
69 return new static( $sect );
70 }
71 }
72
83 public function replaceSection( $sectionId, Content $with, $sectionTitle = '' ) {
84 $myModelId = $this->getModel();
85 $sectionModelId = $with->getModel();
86
87 if ( $sectionModelId != $myModelId ) {
88 throw new MWException( "Incompatible content model for section: " .
89 "document uses $myModelId but " .
90 "section uses $sectionModelId." );
91 }
93 '@phan-var self $with';
94
95 $oldtext = $this->getText();
96 $text = $with->getText();
97
98 if ( strval( $sectionId ) === '' ) {
99 return $with; # XXX: copy first?
100 }
101
102 if ( $sectionId === 'new' ) {
103 # Inserting a new section
104 $subject = $sectionTitle ? wfMessage( 'newsectionheaderdefaultlevel' )
105 ->plaintextParams( $sectionTitle )->inContentLanguage()->text() . "\n\n" : '';
106 if ( Hooks::run( 'PlaceNewSection', [ $this, $oldtext, $subject, &$text ] ) ) {
107 $text = strlen( trim( $oldtext ) ) > 0
108 ? "{$oldtext}\n\n{$subject}{$text}"
109 : "{$subject}{$text}";
110 }
111 } else {
112 # Replacing an existing section; roll out the big guns
113 $text = MediaWikiServices::getInstance()->getParser()
114 ->replaceSection( $oldtext, $sectionId, $text );
115 }
116
117 $newContent = new static( $text );
118
119 return $newContent;
120 }
121
130 public function addSectionHeader( $header ) {
131 $text = wfMessage( 'newsectionheaderdefaultlevel' )
132 ->rawParams( $header )->inContentLanguage()->text();
133 $text .= "\n\n";
134 $text .= $this->getText();
135
136 return new static( $text );
137 }
138
149 public function preSaveTransform( Title $title, User $user, ParserOptions $popts ) {
150 $text = $this->getText();
151
152 $parser = MediaWikiServices::getInstance()->getParser();
153 $pst = $parser->preSaveTransform( $text, $title, $user, $popts );
154
155 if ( $text === $pst ) {
156 return $this;
157 }
158
159 $ret = new static( $pst );
160
161 if ( $parser->getOutput()->getFlag( 'user-signature' ) ) {
162 $ret->hadSignature = true;
163 }
164
165 return $ret;
166 }
167
178 public function preloadTransform( Title $title, ParserOptions $popts, $params = [] ) {
179 $text = $this->getText();
180 $plt = MediaWikiServices::getInstance()->getParser()
181 ->getPreloadText( $text, $title, $popts, $params );
182
183 return new static( $plt );
184 }
185
195 protected function getRedirectTargetAndText() {
196 global $wgMaxRedirects;
197
198 if ( $this->redirectTargetAndText !== null ) {
200 }
201
202 if ( $wgMaxRedirects < 1 ) {
203 // redirects are disabled, so quit early
204 $this->redirectTargetAndText = [ null, $this->getText() ];
206 }
207
208 $redir = MediaWikiServices::getInstance()->getMagicWordFactory()->get( 'redirect' );
209 $text = ltrim( $this->getText() );
210 if ( $redir->matchStartAndRemove( $text ) ) {
211 // Extract the first link and see if it's usable
212 // Ensure that it really does come directly after #REDIRECT
213 // Some older redirects included a colon, so don't freak about that!
214 $m = [];
215 if ( preg_match( '!^\s*:?\s*\[{2}(.*?)(?:\|.*?)?\]{2}\s*!', $text, $m ) ) {
216 // Strip preceding colon used to "escape" categories, etc.
217 // and URL-decode links
218 if ( strpos( $m[1], '%' ) !== false ) {
219 // Match behavior of inline link parsing here;
220 $m[1] = rawurldecode( ltrim( $m[1], ':' ) );
221 }
222 $title = Title::newFromText( $m[1] );
223 // If the title is a redirect to bad special pages or is invalid, return null
224 if ( !$title instanceof Title || !$title->isValidRedirectTarget() ) {
225 $this->redirectTargetAndText = [ null, $this->getText() ];
227 }
228
229 $this->redirectTargetAndText = [ $title, substr( $text, strlen( $m[0] ) ) ];
231 }
232 }
233
234 $this->redirectTargetAndText = [ null, $this->getText() ];
236 }
237
245 public function getRedirectTarget() {
246 list( $title, ) = $this->getRedirectTargetAndText();
247
248 return $title;
249 }
250
263 public function updateRedirect( Title $target ) {
264 if ( !$this->isRedirect() ) {
265 return $this;
266 }
267
268 # Fix the text
269 # Remember that redirect pages can have categories, templates, etc.,
270 # so the regex has to be fairly general
271 $newText = preg_replace( '/ \[ \[ [^\]]* \] \] /x',
272 '[[' . $target->getFullText() . ']]',
273 $this->getText(), 1 );
274
275 return new static( $newText );
276 }
277
289 public function isCountable( $hasLinks = null, Title $title = null ) {
291
292 if ( $this->isRedirect() ) {
293 return false;
294 }
295
296 if ( $wgArticleCountMethod === 'link' ) {
297 if ( $hasLinks === null ) { # not known, find out
298 if ( !$title ) {
299 $context = RequestContext::getMain();
300 $title = $context->getTitle();
301 }
302
303 $po = $this->getParserOutput( $title, null, null, false );
304 $links = $po->getLinks();
305 $hasLinks = !empty( $links );
306 }
307
308 return $hasLinks;
309 }
310
311 return true;
312 }
313
318 public function getTextForSummary( $maxlength = 250 ) {
319 $truncatedtext = parent::getTextForSummary( $maxlength );
320
321 # clean up unfinished links
322 # XXX: make this optional? wasn't there in autosummary, but required for
323 # deletion summary.
324 $truncatedtext = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $truncatedtext );
325
326 return $truncatedtext;
327 }
328
341 protected function fillParserOutput( Title $title, $revId,
342 ParserOptions $options, $generateHtml, ParserOutput &$output
343 ) {
344 $stackTrace = ( new RuntimeException() )->getTraceAsString();
345 if ( $this->previousParseStackTrace ) {
346 // NOTE: there may be legitimate changes to re-parse the same WikiText content,
347 // e.g. if predicted revision ID for the REVISIONID magic word mismatched.
348 // But that should be rare.
349 $logger = LoggerFactory::getInstance( 'DuplicateParse' );
350 $logger->debug(
351 __METHOD__ . ': Possibly redundant parse!',
352 [
353 'title' => $title->getPrefixedDBkey(),
354 'rev' => $revId,
355 'options-hash' => $options->optionsHash(
356 ParserOptions::allCacheVaryingOptions(),
357 $title
358 ),
359 'trace' => $stackTrace,
360 'previous-trace' => $this->previousParseStackTrace,
361 ]
362 );
363 }
364 $this->previousParseStackTrace = $stackTrace;
365
366 list( $redir, $text ) = $this->getRedirectTargetAndText();
367 $output = MediaWikiServices::getInstance()->getParser()
368 ->parse( $text, $title, $options, true, true, $revId );
369
370 // Add redirect indicator at the top
371 if ( $redir ) {
372 // Make sure to include the redirect link in pagelinks
373 $output->addLink( $redir );
374 if ( $generateHtml ) {
375 $chain = $this->getRedirectChain();
376 $output->setText(
377 Article::getRedirectHeaderHtml( $title->getPageLanguage(), $chain, false ) .
378 $output->getRawText()
379 );
380 $output->addModuleStyles( 'mediawiki.action.view.redirectPage' );
381 }
382 }
383
384 // Pass along user-signature flag
385 if ( $this->hadSignature ) {
386 $output->setFlag( 'user-signature' );
387 }
388 }
389
393 protected function getHtml() {
394 throw new MWException(
395 "getHtml() not implemented for wikitext. "
396 . "Use getParserOutput()->getText()."
397 );
398 }
399
409 public function matchMagicWord( MagicWord $word ) {
410 return $word->match( $this->getText() );
411 }
412
413}
$wgMaxRedirects
Max number of redirects to follow when resolving redirects.
$wgArticleCountMethod
Method used to determine if a page in a content namespace should be counted as a valid article.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
getParserOutput(Title $title, $revId=null, ParserOptions $options=null, $generateHtml=true)
Returns a ParserOutput object containing information derived from this content.
static getRedirectHeaderHtml(Language $lang, $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
Definition Article.php:1713
MediaWiki exception.
This class encapsulates "magic words" such as "#redirect", NOTOC, etc.
Definition MagicWord.php:57
match( $text)
Returns true if the text contains the word.
PSR-3 logger instance factory.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Set options of the Parser.
optionsHash( $forOptions, $title=null)
Generate a hash string with the values set on these ParserOptions for the keys given in the array.
addLink(Title $title, $id=null)
Record a local or interwiki inline link for saving in future link tables.
getRawText()
Get the cacheable text with <mw:editsection> markers still in it.
addModuleStyles( $modules)
setFlag( $flag)
Attach a flag to the output so that it can be checked later to handle special cases.
Content object implementation for representing flat text.
getText()
Returns the text represented by this Content object, as a string.
Represents a title within MediaWiki.
Definition Title.php:42
getFullText()
Get the prefixed title with spaces, plus any fragment (part beginning with '#')
Definition Title.php:1842
isValidRedirectTarget()
Check if this Title is a valid redirect target.
Definition Title.php:4492
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:51
Content object for wiki text pages.
updateRedirect(Title $target)
This implementation replaces the first link on the page with the given new target if this Content obj...
getRedirectTarget()
Implement redirect extraction for wikitext.
array null $previousParseStackTrace
Stack trace of the previous parse.
getTextForSummary( $maxlength=250)
preloadTransform(Title $title, ParserOptions $popts, $params=[])
Returns a Content object with preload transformations applied (or this object if no transformations a...
fillParserOutput(Title $title, $revId, ParserOptions $options, $generateHtml, ParserOutput &$output)
Returns a ParserOutput object resulting from parsing the content's text using the global Parser servi...
getRedirectTargetAndText()
Extract the redirect target and the remaining text on the page.
addSectionHeader( $header)
Returns a new WikitextContent object with the given section heading prepended.
isCountable( $hasLinks=null, Title $title=null)
Returns true if this content is not a redirect, and this content's text is countable according to the...
getSection( $sectionId)
matchMagicWord(MagicWord $word)
This implementation calls $word->match() on the this TextContent object's text.
bool $hadSignature
Tracks if the parser set the user-signature flag when creating this content, which would make it expi...
preSaveTransform(Title $title, User $user, ParserOptions $popts)
Returns a Content object with pre-save transformations applied using Parser::preSaveTransform().
replaceSection( $sectionId, Content $with, $sectionTitle='')
const CONTENT_MODEL_WIKITEXT
Definition Defines.php:224
Base interface for content objects.
Definition Content.php:34
getModel()
Returns the ID of the content model used by this Content object.
replaceSection( $sectionId, Content $with, $sectionTitle='')
Replaces a section of the content and returns a Content object with the section replaced.
$context
Definition load.php:45
$header