MediaWiki  master
PoolWorkArticleView.php
Go to the documentation of this file.
1 <?php
27 
30  private $page;
31 
33  private $cacheKey;
34 
36  private $revid;
37 
39  private $parserCache;
40 
42  private $parserOptions;
43 
45  private $revision = null;
46 
48  private $audience;
49 
51  private $revisionStore = null;
52 
54  private $renderer = null;
55 
57  private $parserOutput = false;
58 
60  private $isDirty = false;
61 
63  private $isFast = false;
64 
66  private $error = false;
67 
79  $revid, $useParserCache, $revision = null, $audience = RevisionRecord::FOR_PUBLIC
80  ) {
81  if ( is_string( $revision ) ) { // BC: very old style call
82  $revRecord = $page->getRevisionRecord();
83  $mainSlot = $revRecord->getSlot( SlotRecord::MAIN, RevisionRecord::RAW );
84  $modelId = $mainSlot->getModel();
85  $format = $mainSlot->getFormat();
86 
87  if ( $format === null ) {
88  $format = MediaWikiServices::getInstance()
89  ->getContentHandlerFactory()
90  ->getContentHandler( $modelId )
91  ->getDefaultFormat();
92  }
93 
94  $revision = ContentHandler::makeContent( $revision, $page->getTitle(), $modelId, $format );
95  }
96 
97  if ( $revision instanceof Content ) { // BC: old style call
100  $revision->setId( $revid );
101  $revision->setPageId( $page->getId() );
102  $revision->setContent( SlotRecord::MAIN, $content );
103  }
104 
105  if ( $revision ) {
106  // Check that the RevisionRecord matches $revid and $page, but still allow
107  // fake RevisionRecords coming from errors or hooks in Article to be rendered.
108  if ( $revision->getId() && $revision->getId() !== $revid ) {
109  throw new InvalidArgumentException( '$revid parameter mismatches $revision parameter' );
110  }
111  if ( $revision->getPageId()
112  && $revision->getPageId() !== $page->getTitle()->getArticleID()
113  ) {
114  throw new InvalidArgumentException( '$page parameter mismatches $revision parameter' );
115  }
116  }
117 
118  // TODO: DI: inject services
119  $this->renderer = MediaWikiServices::getInstance()->getRevisionRenderer();
120  $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
121  $this->parserCache = MediaWikiServices::getInstance()->getParserCache();
122 
123  $this->page = $page;
124  $this->revid = $revid;
125  $this->cacheable = $useParserCache;
126  $this->parserOptions = $parserOptions;
127  $this->revision = $revision;
128  $this->audience = $audience;
129  $this->cacheKey = $this->parserCache->getKey( $page, $parserOptions );
130  $keyPrefix = $this->cacheKey ?: ObjectCache::getLocalClusterInstance()->makeKey(
131  'articleview', 'missingcachekey'
132  );
133 
134  parent::__construct( 'ArticleView', $keyPrefix . ':revid:' . $revid );
135  }
136 
142  public function getParserOutput() {
143  return $this->parserOutput;
144  }
145 
151  public function getIsDirty() {
152  return $this->isDirty;
153  }
154 
160  public function getIsFastStale() {
161  return $this->isFast;
162  }
163 
169  public function getError() {
170  return $this->error;
171  }
172 
176  public function doWork() {
177  global $wgUseFileCache;
178 
179  // @todo several of the methods called on $this->page are not declared in Page, but present
180  // in WikiPage and delegated by Article.
181 
182  $isCurrent = $this->revid === $this->page->getLatest();
183 
184  // The current revision cannot be hidden so we can skip some checks.
185  $audience = $isCurrent ? RevisionRecord::RAW : $this->audience;
186 
187  if ( $this->revision !== null ) {
188  $rev = $this->revision;
189  } elseif ( $isCurrent ) {
190  $rev = $this->page->getRevisionRecord();
191  } else {
192  $rev = $this->revisionStore->getRevisionByTitle( $this->page->getTitle(), $this->revid );
193  }
194 
195  if ( !$rev ) {
196  // couldn't load
197  return false;
198  }
199 
200  $renderedRevision = $this->renderer->getRenderedRevision(
201  $rev,
202  $this->parserOptions,
203  null,
204  [ 'audience' => $audience ]
205  );
206 
207  if ( !$renderedRevision ) {
208  // audience check failed
209  return false;
210  }
211 
212  // Reduce effects of race conditions for slow parses (T48014)
213  $cacheTime = wfTimestampNow();
214 
215  $time = - microtime( true );
216  $this->parserOutput = $renderedRevision->getRevisionParserOutput();
217  $time += microtime( true );
218 
219  // Timing hack
220  if ( $time > 3 ) {
221  // TODO: Use Parser's logger (once it has one)
222  $logger = MediaWiki\Logger\LoggerFactory::getInstance( 'slow-parse' );
223  $logger->info( '{time} {title}', [
224  'time' => number_format( $time, 2 ),
225  'title' => $this->page->getTitle()->getPrefixedDBkey(),
226  'ns' => $this->page->getTitle()->getNamespace(),
227  'trigger' => 'view',
228  ] );
229  }
230 
231  if ( $this->cacheable && $this->parserOutput->isCacheable() && $isCurrent ) {
232  $this->parserCache->save(
233  $this->parserOutput, $this->page, $this->parserOptions, $cacheTime, $this->revid );
234  }
235 
236  // Make sure file cache is not used on uncacheable content.
237  // Output that has magic words in it can still use the parser cache
238  // (if enabled), though it will generally expire sooner.
239  if ( !$this->parserOutput->isCacheable() ) {
240  $wgUseFileCache = false;
241  }
242 
243  if ( $isCurrent ) {
244  $this->page->triggerOpportunisticLinksUpdate( $this->parserOutput );
245  }
246 
247  return true;
248  }
249 
253  public function getCachedWork() {
254  $this->parserOutput = $this->parserCache->get( $this->page, $this->parserOptions );
255 
256  if ( $this->parserOutput === false ) {
257  wfDebug( __METHOD__ . ": parser cache miss" );
258  return false;
259  } else {
260  wfDebug( __METHOD__ . ": parser cache hit" );
261  return true;
262  }
263  }
264 
269  public function fallback( $fast ) {
270  $this->parserOutput = $this->parserCache->getDirty( $this->page, $this->parserOptions );
271 
272  $fastMsg = '';
273  if ( $this->parserOutput && $fast ) {
274  /* Check if the stale response is from before the last write to the
275  * DB by this user. Declining to return a stale response in this
276  * case ensures that the user will see their own edit after page
277  * save.
278  *
279  * Note that the CP touch time is the timestamp of the shutdown of
280  * the save request, so there is a bias towards avoiding fast stale
281  * responses of potentially several seconds.
282  */
283  $lastWriteTime = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()
284  ->getChronologyProtectorTouched();
285  $cacheTime = MWTimestamp::convert( TS_UNIX, $this->parserOutput->getCacheTime() );
286  if ( $lastWriteTime && $cacheTime <= $lastWriteTime ) {
287  wfDebugLog( 'dirty', "declining to send dirty output since cache time " .
288  $cacheTime . " is before last write time $lastWriteTime" );
289  // Forget this ParserOutput -- we will request it again if
290  // necessary in slow mode. There might be a newer entry
291  // available by that time.
292  $this->parserOutput = false;
293  return false;
294  }
295  $this->isFast = true;
296  $fastMsg = 'fast ';
297  }
298 
299  if ( $this->parserOutput === false ) {
300  wfDebugLog( 'dirty', 'dirty missing' );
301  return false;
302  } else {
303  wfDebugLog( 'dirty', "{$fastMsg}dirty output {$this->cacheKey}" );
304  $this->isDirty = true;
305  return true;
306  }
307  }
308 
313  public function error( $status ) {
314  $this->error = $status;
315  return false;
316  }
317 }
ParserOptions
Set options of the Parser.
Definition: ParserOptions.php:44
Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:46
WikiPage\getRevisionRecord
getRevisionRecord()
Get the latest revision.
Definition: WikiPage.php:744
ParserOutput
Definition: ParserOutput.php:25
ObjectCache\getLocalClusterInstance
static getLocalClusterInstance()
Get the main cluster-local cache object.
Definition: ObjectCache.php:272
PoolWorkArticleView\doWork
doWork()
Definition: PoolWorkArticleView.php:176
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:154
Revision\RevisionStore
Service for looking up page revisions.
Definition: RevisionStore.php:81
MediaWiki\Logger\LoggerFactory\getInstance
static getInstance( $channel)
Get a named logger instance from the currently configured logger factory.
Definition: LoggerFactory.php:92
PoolWorkArticleView\__construct
__construct(WikiPage $page, ParserOptions $parserOptions, $revid, $useParserCache, $revision=null, $audience=RevisionRecord::FOR_PUBLIC)
Definition: PoolWorkArticleView.php:78
WikiPage
Class representing a MediaWiki article and history.
Definition: WikiPage.php:52
PoolWorkArticleView\$renderer
RevisionRenderer $renderer
Definition: PoolWorkArticleView.php:54
PoolWorkArticleView\fallback
fallback( $fast)
Definition: PoolWorkArticleView.php:269
PoolWorkArticleView
Definition: PoolWorkArticleView.php:28
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:988
PoolWorkArticleView\$page
WikiPage $page
Definition: PoolWorkArticleView.php:30
PoolWorkArticleView\$audience
int $audience
Definition: PoolWorkArticleView.php:48
Status
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:44
PoolWorkArticleView\$parserOptions
ParserOptions $parserOptions
Definition: PoolWorkArticleView.php:42
PoolWorkArticleView\$parserOutput
ParserOutput bool $parserOutput
Definition: PoolWorkArticleView.php:57
PoolWorkArticleView\$revid
int $revid
Definition: PoolWorkArticleView.php:36
PoolWorkArticleView\$error
Status bool $error
Definition: PoolWorkArticleView.php:66
$wgUseFileCache
$wgUseFileCache
This will cache static pages for non-logged-in users to reduce database traffic on public sites.
Definition: DefaultSettings.php:2790
WikiPage\getId
getId()
Definition: WikiPage.php:541
WikiPage\getTitle
getTitle()
Get the title object of the article.
Definition: WikiPage.php:281
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1837
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:909
Revision\RevisionRecord\getPageId
getPageId()
Get the page ID.
Definition: RevisionRecord.php:331
PoolWorkArticleView\$revisionStore
RevisionStore $revisionStore
Definition: PoolWorkArticleView.php:51
ContentHandler\makeContent
static makeContent( $text, Title $title=null, $modelId=null, $format=null)
Convenience function for creating a Content object from a given textual representation.
Definition: ContentHandler.php:142
Revision\RevisionRecord\getId
getId()
Get revision ID.
Definition: RevisionRecord.php:279
PoolWorkArticleView\$cacheKey
string $cacheKey
Definition: PoolWorkArticleView.php:33
PoolWorkArticleView\getIsFastStale
getIsFastStale()
Get whether the ParserOutput was retrieved in fast stale mode.
Definition: PoolWorkArticleView.php:160
PoolWorkArticleView\getError
getError()
Get a Status object in case of error or false otherwise.
Definition: PoolWorkArticleView.php:169
Revision\RevisionRenderer
The RevisionRenderer service provides access to rendered output for revisions.
Definition: RevisionRenderer.php:45
$content
$content
Definition: router.php:76
Revision\MutableRevisionRecord
Definition: MutableRevisionRecord.php:45
Content
Base interface for content objects.
Definition: Content.php:35
PoolWorkArticleView\$isFast
bool $isFast
Definition: PoolWorkArticleView.php:63
ParserCache
Definition: ParserCache.php:32
PoolCounterWork
Class for dealing with PoolCounters using class members.
Definition: PoolCounterWork.php:27
PoolWorkArticleView\getParserOutput
getParserOutput()
Get the ParserOutput from this object, or false in case of failure.
Definition: PoolWorkArticleView.php:142
PoolWorkArticleView\error
error( $status)
Definition: PoolWorkArticleView.php:313
PoolWorkArticleView\$isDirty
bool $isDirty
Definition: PoolWorkArticleView.php:60
PoolWorkArticleView\$parserCache
ParserCache $parserCache
Definition: PoolWorkArticleView.php:39
PoolWorkArticleView\$revision
RevisionRecord null $revision
Definition: PoolWorkArticleView.php:45
PoolWorkArticleView\getCachedWork
getCachedWork()
Definition: PoolWorkArticleView.php:253
PoolWorkArticleView\getIsDirty
getIsDirty()
Get whether the ParserOutput is a dirty one (i.e.
Definition: PoolWorkArticleView.php:151
Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:39