MediaWiki REL1_39
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,
99 TitleFactory $titleFactory,
100 $reboundDelay,
101 $useFileCache,
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.
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...
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.