MediaWiki  master
HtmlCacheUpdater.php
Go to the documentation of this file.
1 <?php
25 
34  private $reboundDelay;
36  private $useFileCache;
38  private $cdnMaxAge;
39 
41  private $hookRunner;
42 
44  public const PURGE_NAIVE = 0;
50  public const PURGE_PRESEND = 1;
55  public const PURGE_REBOUND = 2;
56 
65  public const PURGE_INTENT_TXROUND_REFLECTED = self::PURGE_PRESEND | self::PURGE_REBOUND;
66 
75  public const PURGE_URLS_LINKSUPDATE_ONLY = 4;
76 
83  public const UNLESS_CACHE_MTIME_AFTER = 'unless-timestamp-exceeds';
84 
86  private $titleFactory;
87 
97  public function __construct(
98  HookContainer $hookContainer,
102  $cdnMaxAge
103  ) {
104  $this->hookRunner = new HookRunner( $hookContainer );
105  $this->titleFactory = $titleFactory;
106  $this->reboundDelay = $reboundDelay;
107  $this->useFileCache = $useFileCache;
108  $this->cdnMaxAge = $cdnMaxAge;
109  }
110 
116  private function fieldHasFlag( $flags, $flag ) {
117  return ( ( $flags & $flag ) === $flag );
118  }
119 
128  public function purgeUrls( $urls, $flags = self::PURGE_PRESEND, array $unless = [] ) {
129  $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
130  if ( $minFreshCacheMtime && time() > ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
131  return;
132  }
133 
134  $urls = is_string( $urls ) ? [ $urls ] : $urls;
135 
136  $reboundDelay = $this->fieldHasFlag( $flags, self::PURGE_REBOUND )
137  ? $this->reboundDelay
138  : 0; // no second purge
139 
140  $update = new CdnCacheUpdate( $urls, [ 'reboundDelay' => $reboundDelay ] );
141  if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
142  DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
143  } else {
144  $update->doUpdate();
145  }
146  }
147 
160  public function purgeTitleUrls( $pages, $flags = self::PURGE_PRESEND, array $unless = [] ) {
161  $pages = is_iterable( $pages ) ? $pages : [ $pages ];
162  $pageIdentities = [];
163 
164  foreach ( $pages as $page ) {
165  // TODO: We really only need to cast to PageIdentity. We could use a LinkBatch for that.
166  $title = $this->titleFactory->castFromPageReference( $page );
167 
168  if ( $title->canExist() ) {
169  $pageIdentities[] = $title;
170  }
171  }
172 
173  if ( !$pageIdentities ) {
174  return;
175  }
176 
177  if ( $this->useFileCache ) {
178  // @phan-suppress-next-line PhanTypeMismatchArgument castFrom does not return null here
179  $update = HtmlFileCacheUpdate::newFromPages( $pageIdentities );
180  if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
181  DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
182  } else {
183  $update->doUpdate();
184  }
185  }
186 
187  $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
188  if ( !$minFreshCacheMtime || time() <= ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
189  $urls = [];
190  foreach ( $pageIdentities as $pi ) {
192  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
193  $urls = array_merge( $urls, $this->getUrls( $pi, $flags ) );
194  }
195  $this->purgeUrls( $urls, $flags );
196  }
197  }
198 
206  public function getUrls( PageReference $page, int $flags = 0 ): array {
207  $title = $this->titleFactory->castFromPageReference( $page );
208 
209  if ( !$title->canExist() ) {
210  return [];
211  }
212 
213  // These urls are affected both by direct revisions as well,
214  // as re-rendering of the same content during a LinksUpdate.
215  $urls = [
216  $title->getInternalURL()
217  ];
218  // Language variant page views are currently not cached
219  // and thus not purged (T250511).
220 
221  // These urls are only affected by direct revisions, and do not require
222  // purging when a LinksUpdate merely rerenders the same content.
223  // This exists to avoid large amounts of redundant PURGE traffic (T250261).
224  if ( !$this->fieldHasFlag( $flags, self::PURGE_URLS_LINKSUPDATE_ONLY ) ) {
225  $urls[] = $title->getInternalURL( 'action=history' );
226 
227  // Canonical action=raw URLs for user and site config pages (T58874, T261371).
228  if ( $title->isUserJsConfigPage() || $title->isSiteJsConfigPage() ) {
229  $urls[] = $title->getInternalURL( 'action=raw&ctype=text/javascript' );
230  } elseif ( $title->isUserJsonConfigPage() || $title->isSiteJsonConfigPage() ) {
231  $urls[] = $title->getInternalURL( 'action=raw&ctype=application/json' );
232  } elseif ( $title->isUserCssConfigPage() || $title->isSiteCssConfigPage() ) {
233  $urls[] = $title->getInternalURL( 'action=raw&ctype=text/css' );
234  }
235  }
236 
237  // Extensions may add novel ways to access this content
238  $append = [];
239  $mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
240  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
241  $this->hookRunner->onHtmlCacheUpdaterAppendUrls( $title, $mode, $append );
242  $urls = array_merge( $urls, $append );
243 
244  // Extensions may add novel ways to access the site overall
245  $append = [];
246  $this->hookRunner->onHtmlCacheUpdaterVaryUrls( $urls, $append );
247  $urls = array_merge( $urls, $append );
248 
249  // Legacy. TODO: Deprecate this
250  // @phan-suppress-next-line PhanTypeMismatchArgumentNullable castFrom does not return null here
251  $this->hookRunner->onTitleSquidURLs( $title, $urls );
252 
253  return $urls;
254  }
255 }
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.
HookRunner $hookRunner
int $cdnMaxAge
Max seconds for CDN to served cached objects without revalidation.
bool $useFileCache
Whether filesystem-based HTML output caching is enabled.
purgeUrls( $urls, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN for a URL or list of URLs.
fieldHasFlag( $flags, $flag)
int $reboundDelay
Seconds between initial and rebound purges; 0 if disabled.
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)
TitleFactory $titleFactory
static newFromPages( $pages)
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Definition: HookRunner.php:562
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.