MediaWiki  master
HtmlCacheUpdater.php
Go to the documentation of this file.
1 <?php
26 
35  private $reboundDelay;
37  private $useFileCache;
39  private $cdnMaxAge;
40 
42  private $hookRunner;
43 
45  public const PURGE_NAIVE = 0;
51  public const PURGE_PRESEND = 1;
56  public const PURGE_REBOUND = 2;
57 
66  public const PURGE_INTENT_TXROUND_REFLECTED = self::PURGE_PRESEND | self::PURGE_REBOUND;
67 
76  public const PURGE_URLS_LINKSUPDATE_ONLY = 4;
77 
84  public const UNLESS_CACHE_MTIME_AFTER = 'unless-timestamp-exceeds';
85 
87  private $titleFactory;
88 
98  public function __construct(
99  HookContainer $hookContainer,
100  TitleFactory $titleFactory,
101  $reboundDelay,
102  $useFileCache,
103  $cdnMaxAge
104  ) {
105  $this->hookRunner = new HookRunner( $hookContainer );
106  $this->titleFactory = $titleFactory;
107  $this->reboundDelay = $reboundDelay;
108  $this->useFileCache = $useFileCache;
109  $this->cdnMaxAge = $cdnMaxAge;
110  }
111 
117  private function fieldHasFlag( $flags, $flag ) {
118  return ( ( $flags & $flag ) === $flag );
119  }
120 
129  public function purgeUrls( $urls, $flags = self::PURGE_PRESEND, array $unless = [] ) {
130  $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
131  if ( $minFreshCacheMtime && time() > ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
132  return;
133  }
134 
135  $urls = is_string( $urls ) ? [ $urls ] : $urls;
136 
137  $reboundDelay = $this->fieldHasFlag( $flags, self::PURGE_REBOUND )
138  ? $this->reboundDelay
139  : 0; // no second purge
140 
141  $update = new CdnCacheUpdate( $urls, [ 'reboundDelay' => $reboundDelay ] );
142  if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
143  DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
144  } else {
145  $update->doUpdate();
146  }
147  }
148 
161  public function purgeTitleUrls( $pages, $flags = self::PURGE_PRESEND, array $unless = [] ) {
162  $pages = is_iterable( $pages ) ? $pages : [ $pages ];
163  $pageIdentities = [];
164 
165  foreach ( $pages as $page ) {
166  // TODO: We really only need to cast to PageIdentity. We could use a LinkBatch for that.
167  $title = $this->titleFactory->castFromPageReference( $page );
168 
169  if ( $title->canExist() ) {
170  $pageIdentities[] = $title;
171  }
172  }
173 
174  if ( !$pageIdentities ) {
175  return;
176  }
177 
178  if ( $this->useFileCache ) {
179  // @phan-suppress-next-line PhanTypeMismatchArgument castFrom does not return null here
180  $update = HtmlFileCacheUpdate::newFromPages( $pageIdentities );
181  if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
182  DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
183  } else {
184  $update->doUpdate();
185  }
186  }
187 
188  $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
189  if ( !$minFreshCacheMtime || time() <= ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
190  $urls = [];
191  foreach ( $pageIdentities as $pi ) {
193  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
194  $urls = array_merge( $urls, $this->getUrls( $pi, $flags ) );
195  }
196  $this->purgeUrls( $urls, $flags );
197  }
198  }
199 
207  public function getUrls( PageReference $page, int $flags = 0 ): array {
208  $title = $this->titleFactory->castFromPageReference( $page );
209 
210  if ( !$title->canExist() ) {
211  return [];
212  }
213 
214  // These urls are affected both by direct revisions as well,
215  // as re-rendering of the same content during a LinksUpdate.
216  $urls = [
217  $title->getInternalURL()
218  ];
219  // Language variant page views are currently not cached
220  // and thus not purged (T250511).
221 
222  // These urls are only affected by direct revisions, and do not require
223  // purging when a LinksUpdate merely rerenders the same content.
224  // This exists to avoid large amounts of redundant PURGE traffic (T250261).
225  if ( !$this->fieldHasFlag( $flags, self::PURGE_URLS_LINKSUPDATE_ONLY ) ) {
226  $urls[] = $title->getInternalURL( 'action=history' );
227 
228  // Canonical action=raw URLs for user and site config pages (T58874, T261371).
229  if ( $title->isUserJsConfigPage() || $title->isSiteJsConfigPage() ) {
230  $urls[] = $title->getInternalURL( 'action=raw&ctype=text/javascript' );
231  } elseif ( $title->isUserJsonConfigPage() || $title->isSiteJsonConfigPage() ) {
232  $urls[] = $title->getInternalURL( 'action=raw&ctype=application/json' );
233  } elseif ( $title->isUserCssConfigPage() || $title->isSiteCssConfigPage() ) {
234  $urls[] = $title->getInternalURL( 'action=raw&ctype=text/css' );
235  }
236  }
237 
238  // Extensions may add novel ways to access this content
239  $append = [];
240  $mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
241  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
242  $this->hookRunner->onHtmlCacheUpdaterAppendUrls( $title, $mode, $append );
243  $urls = array_merge( $urls, $append );
244 
245  // Extensions may add novel ways to access the site overall
246  $append = [];
247  $this->hookRunner->onHtmlCacheUpdaterVaryUrls( $urls, $append );
248  $urls = array_merge( $urls, $append );
249 
250  // Legacy. TODO: Deprecate this
251  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
252  $this->hookRunner->onTitleSquidURLs( $title, $urls );
253 
254  return $urls;
255  }
256 }
Handles purging the appropriate CDN objects given a list of URLs or Title instances.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the pending update queue for execution at the appropriate time.
Class to invalidate the CDN and HTMLFileCache entries associated with URLs/titles.
purgeUrls( $urls, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN for a URL or list of URLs.
getUrls(PageReference $page, int $flags=0)
Get a list of URLs to purge from the CDN cache when this page changes.
purgeTitleUrls( $pages, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN/HTMLFileCache for a title or the titles yielded by an iterator.
__construct(HookContainer $hookContainer, TitleFactory $titleFactory, $reboundDelay, $useFileCache, $cdnMaxAge)
static newFromPages( $pages)
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:560
Creates Title objects.
Interface for objects (potentially) representing an editable wiki page.
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.