MediaWiki master
HTMLCacheUpdater.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Cache;
8
17use Traversable;
18
27 private $reboundDelay;
29 private $useFileCache;
31 private $cdnMaxAge;
32
34 private $hookRunner;
35
37 public const PURGE_NAIVE = 0;
43 public const PURGE_PRESEND = 1;
48 public const PURGE_REBOUND = 2;
49
58 public const PURGE_INTENT_TXROUND_REFLECTED = self::PURGE_PRESEND | self::PURGE_REBOUND;
59
68 public const PURGE_URLS_LINKSUPDATE_ONLY = 4;
69
76 public const UNLESS_CACHE_MTIME_AFTER = 'unless-timestamp-exceeds';
77
79 private $titleFactory;
80
90 public function __construct(
91 HookContainer $hookContainer,
92 TitleFactory $titleFactory,
93 $reboundDelay,
94 $useFileCache,
95 $cdnMaxAge
96 ) {
97 $this->hookRunner = new HookRunner( $hookContainer );
98 $this->titleFactory = $titleFactory;
99 $this->reboundDelay = $reboundDelay;
100 $this->useFileCache = $useFileCache;
101 $this->cdnMaxAge = $cdnMaxAge;
102 }
103
109 private function fieldHasFlag( $flags, $flag ) {
110 return ( ( $flags & $flag ) === $flag );
111 }
112
121 public function purgeUrls( $urls, $flags = self::PURGE_PRESEND, array $unless = [] ) {
122 $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
123 if ( $minFreshCacheMtime && time() > ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
124 return;
125 }
126
127 $urls = is_string( $urls ) ? [ $urls ] : $urls;
128
129 $reboundDelay = $this->fieldHasFlag( $flags, self::PURGE_REBOUND )
130 ? $this->reboundDelay
131 : 0; // no second purge
132
133 $update = new CdnCacheUpdate( $urls, [ 'reboundDelay' => $reboundDelay ] );
134 if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
135 DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
136 } else {
137 $update->doUpdate();
138 }
139 }
140
153 public function purgeTitleUrls( $pages, $flags = self::PURGE_PRESEND, array $unless = [] ) {
154 $pages = is_iterable( $pages ) ? $pages : [ $pages ];
155 $pageIdentities = [];
156
157 foreach ( $pages as $page ) {
158 // TODO: We really only need to cast to PageIdentity. We could use a LinkBatch for that.
159 $title = $this->titleFactory->newFromPageReference( $page );
160
161 if ( $title->canExist() ) {
162 $pageIdentities[] = $title;
163 }
164 }
165
166 if ( !$pageIdentities ) {
167 return;
168 }
169
170 if ( $this->useFileCache ) {
171 $update = HtmlFileCacheUpdate::newFromPages( $pageIdentities );
172 if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
173 DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
174 } else {
175 $update->doUpdate();
176 }
177 }
178
179 $minFreshCacheMtime = $unless[self::UNLESS_CACHE_MTIME_AFTER] ?? null;
180 if ( !$minFreshCacheMtime || time() <= ( $minFreshCacheMtime + $this->cdnMaxAge ) ) {
181 $urls = [];
182 foreach ( $pageIdentities as $pi ) {
184 $urls = array_merge( $urls, $this->getUrls( $pi, $flags ) );
185 }
186 $this->purgeUrls( $urls, $flags );
187 }
188 }
189
197 public function getUrls( PageReference $page, int $flags = 0 ): array {
198 $title = $this->titleFactory->newFromPageReference( $page );
199
200 if ( !$title->canExist() ) {
201 return [];
202 }
203
204 // These urls are affected both by direct revisions as well,
205 // as re-rendering of the same content during a LinksUpdate.
206 $urls = [
207 $title->getInternalURL()
208 ];
209 // Language variant page views are currently not cached
210 // and thus not purged (T250511).
211
212 // These urls are only affected by direct revisions, and do not require
213 // purging when a LinksUpdate merely rerenders the same content.
214 // This exists to avoid large amounts of redundant PURGE traffic (T250261).
215 if ( !$this->fieldHasFlag( $flags, self::PURGE_URLS_LINKSUPDATE_ONLY ) ) {
216 $urls[] = $title->getInternalURL( 'action=history' );
217
218 // Canonical action=raw URLs for user and site config pages (T58874, T261371).
219 if ( $title->isUserJsConfigPage() || $title->isSiteJsConfigPage() ) {
220 $urls[] = $title->getInternalURL( 'action=raw&ctype=text/javascript' );
221 } elseif ( $title->isUserJsonConfigPage() || $title->isSiteJsonConfigPage() ) {
222 $urls[] = $title->getInternalURL( 'action=raw&ctype=application/json' );
223 } elseif ( $title->isUserCssConfigPage() || $title->isSiteCssConfigPage() ) {
224 $urls[] = $title->getInternalURL( 'action=raw&ctype=text/css' );
225 }
226 }
227
228 // Extensions may add novel ways to access this content
229 $append = [];
230 $mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
231 $this->hookRunner->onHtmlCacheUpdaterAppendUrls( $title, $mode, $append );
232 $urls = array_merge( $urls, $append );
233
234 // Extensions may add novel ways to access the site overall
235 $append = [];
236 $this->hookRunner->onHtmlCacheUpdaterVaryUrls( $urls, $append );
237 $urls = array_merge( $urls, $append );
238
239 // Legacy. TODO: Deprecate this
240 $this->hookRunner->onTitleSquidURLs( $title, $urls );
241
242 return $urls;
243 }
244}
245
247class_alias( HTMLCacheUpdater::class, 'HtmlCacheUpdater' );
Class to invalidate the CDN and HTMLFileCache entries associated with URLs/titles.
purgeTitleUrls( $pages, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN/HTMLFileCache for a title or the titles yielded by an iterator.
getUrls(PageReference $page, int $flags=0)
Get a list of URLs to purge from the CDN cache when this page changes.
__construct(HookContainer $hookContainer, TitleFactory $titleFactory, $reboundDelay, $useFileCache, $cdnMaxAge)
purgeUrls( $urls, $flags=self::PURGE_PRESEND, array $unless=[])
Purge the CDN for a URL or list of URLs.
Handles purging the appropriate CDN objects given a list of URLs or Title instances.
Defer callable updates to run later in the PHP process.
HTMLFileCache purge update for a set of titles.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
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.