]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/parser/ParserOutput.php
MediaWiki 1.17.0
[autoinstalls/mediawiki.git] / includes / parser / ParserOutput.php
1 <?php
2 /**
3  * Output of the PHP parser
4  *
5  * @file
6  * @ingroup Parser
7  */
8  
9 /**
10  * @todo document
11  * @ingroup Parser
12  */
13
14 class CacheTime {
15         var     $mVersion = Parser::VERSION,  # Compatibility check
16                 $mCacheTime = '',             # Time when this object was generated, or -1 for uncacheable. Used in ParserCache.
17                 $mCacheExpiry = null,         # Seconds after which the object should expire, use 0 for uncachable. Used in ParserCache.
18                 $mContainsOldMagic;           # Boolean variable indicating if the input contained variables like {{CURRENTDAY}}
19                 
20         function getCacheTime()              { return $this->mCacheTime; }
21
22         function containsOldMagic()          { return $this->mContainsOldMagic; }
23         function setContainsOldMagic( $com ) { return wfSetVar( $this->mContainsOldMagic, $com ); }
24         
25         /** 
26          * setCacheTime() sets the timestamp expressing when the page has been rendered. 
27          * This doesn not control expiry, see updateCacheExpiry() for that!
28          */
29         function setCacheTime( $t )          { return wfSetVar( $this->mCacheTime, $t ); } 
30
31                 
32         /** 
33          * Sets the number of seconds after which this object should expire.
34          * This value is used with the ParserCache.
35          * If called with a value greater than the value provided at any previous call, 
36          * the new call has no effect. The value returned by getCacheExpiry is smaller
37          * or equal to the smallest number that was provided as an argument to 
38          * updateCacheExpiry().
39          */
40         function updateCacheExpiry( $seconds ) { 
41                 $seconds = (int)$seconds;
42
43                 if ( $this->mCacheExpiry === null || $this->mCacheExpiry > $seconds ) 
44                         $this->mCacheExpiry = $seconds; 
45
46                 // hack: set old-style marker for uncacheable entries.
47                 if ( $this->mCacheExpiry !== null && $this->mCacheExpiry <= 0 ) 
48                         $this->mCacheTime = -1;
49         }
50         
51         /**
52          * Returns the number of seconds after which this object should expire.
53          * This method is used by ParserCache to determine how long the ParserOutput can be cached.
54          * The timestamp of expiry can be calculated by adding getCacheExpiry() to getCacheTime().
55          * The value returned by getCacheExpiry is smaller or equal to the smallest number 
56          * that was provided to a call of updateCacheExpiry(), and smaller or equal to the
57          * value of $wgParserCacheExpireTime.
58          */
59         function getCacheExpiry() { 
60                 global $wgParserCacheExpireTime;
61
62                 if ( $this->mCacheTime < 0 ) return 0; // old-style marker for "not cachable"
63
64                 $expire = $this->mCacheExpiry; 
65
66                 if ( $expire === null ) 
67                         $expire = $wgParserCacheExpireTime;
68                 else
69                         $expire = min( $expire, $wgParserCacheExpireTime );
70
71                 if( $this->containsOldMagic() ) { //compatibility hack
72                         $expire = min( $expire, 3600 ); # 1 hour
73                 } 
74
75                 if ( $expire <= 0 ) return 0; // not cachable
76                 else return $expire;
77         }
78
79
80         function isCacheable() { 
81                 return $this->getCacheExpiry() > 0;
82         }
83         
84         /**
85          * Return true if this cached output object predates the global or
86          * per-article cache invalidation timestamps, or if it comes from
87          * an incompatible older version.
88          *
89          * @param $touched String: the affected article's last touched timestamp
90          * @return Boolean
91          */
92         public function expired( $touched ) {
93                 global $wgCacheEpoch;
94                 return !$this->isCacheable() || // parser says it's uncacheable
95                        $this->getCacheTime() < $touched ||
96                        $this->getCacheTime() <= $wgCacheEpoch ||
97                        $this->getCacheTime() < wfTimestamp( TS_MW, time() - $this->getCacheExpiry() ) || // expiry period has passed
98                        !isset( $this->mVersion ) ||
99                        version_compare( $this->mVersion, Parser::VERSION, "lt" );
100         }               
101 }
102  
103 class ParserOutput extends CacheTime
104 {
105         var $mText,                       # The output text
106                 $mLanguageLinks,              # List of the full text of language links, in the order they appear
107                 $mCategories,                 # Map of category names to sort keys
108                 $mTitleText,                  # title text of the chosen language variant
109                 $mLinks = array(),            # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken.
110                 $mTemplates = array(),        # 2-D map of NS/DBK to ID for the template references. ID=zero for broken.
111                 $mTemplateIds = array(),      # 2-D map of NS/DBK to rev ID for the template references. ID=zero for broken.
112                 $mImages = array(),           # DB keys of the images used, in the array key only
113                 $mExternalLinks = array(),    # External link URLs, in the key only
114                 $mInterwikiLinks = array(),   # 2-D map of prefix/DBK (in keys only) for the inline interwiki links in the document.
115                 $mNewSection = false,         # Show a new section link?
116                 $mHideNewSection = false,     # Hide the new section link?
117                 $mNoGallery = false,          # No gallery on category page? (__NOGALLERY__)
118                 $mHeadItems = array(),        # Items to put in the <head> section
119                 $mModules = array(),          # Modules to be loaded by the resource loader
120                 $mOutputHooks = array(),      # Hook tags as per $wgParserOutputHooks
121                 $mWarnings = array(),         # Warning text to be returned to the user. Wikitext formatted, in the key only
122                 $mSections = array(),         # Table of contents
123                 $mProperties = array(),       # Name/value pairs to be cached in the DB
124                 $mTOCHTML = '';               # HTML of the TOC
125         private $mIndexPolicy = '';           # 'index' or 'noindex'?  Any other value will result in no change.
126         private $mAccessedOptions = null; # List of ParserOptions (stored in the keys)
127
128         function __construct( $text = '', $languageLinks = array(), $categoryLinks = array(),
129                 $containsOldMagic = false, $titletext = '' )
130         {
131                 $this->mText = $text;
132                 $this->mLanguageLinks = $languageLinks;
133                 $this->mCategories = $categoryLinks;
134                 $this->mContainsOldMagic = $containsOldMagic;
135                 $this->mTitleText = $titletext;
136         }
137
138         function getText()                   { return $this->mText; }
139         function &getLanguageLinks()         { return $this->mLanguageLinks; }
140         function getInterwikiLinks()         { return $this->mInterwikiLinks; }
141         function getCategoryLinks()          { return array_keys( $this->mCategories ); }
142         function &getCategories()            { return $this->mCategories; }
143         function getTitleText()              { return $this->mTitleText; }
144         function getSections()               { return $this->mSections; }
145         function &getLinks()                 { return $this->mLinks; }
146         function &getTemplates()             { return $this->mTemplates; }
147         function &getImages()                { return $this->mImages; }
148         function &getExternalLinks()         { return $this->mExternalLinks; }
149         function getNoGallery()              { return $this->mNoGallery; }
150         function getHeadItems()              { return $this->mHeadItems; }
151         function getModules()                { return $this->mModules; }
152         function getSubtitle()               { return $this->mSubtitle; }
153         function getOutputHooks()            { return (array)$this->mOutputHooks; }
154         function getWarnings()               { return array_keys( $this->mWarnings ); }
155         function getIndexPolicy()            { return $this->mIndexPolicy; }
156         function getTOCHTML()                { return $this->mTOCHTML; }
157
158         function setText( $text )            { return wfSetVar( $this->mText, $text ); }
159         function setLanguageLinks( $ll )     { return wfSetVar( $this->mLanguageLinks, $ll ); }
160         function setCategoryLinks( $cl )     { return wfSetVar( $this->mCategories, $cl ); }
161
162         function setTitleText( $t )          { return wfSetVar( $this->mTitleText, $t ); }
163         function setSections( $toc )         { return wfSetVar( $this->mSections, $toc ); }
164         function setIndexPolicy( $policy )   { return wfSetVar( $this->mIndexPolicy, $policy ); }
165         function setTOCHTML( $tochtml )      { return wfSetVar( $this->mTOCHTML, $tochtml ); }
166
167         function addCategory( $c, $sort )    { $this->mCategories[$c] = $sort; }
168         function addLanguageLink( $t )       { $this->mLanguageLinks[] = $t; }
169         function addWarning( $s )            { $this->mWarnings[$s] = 1; }
170
171         function addOutputHook( $hook, $data = false ) {
172                 $this->mOutputHooks[] = array( $hook, $data );
173         }
174
175         function setNewSection( $value ) {
176                 $this->mNewSection = (bool)$value;
177         }
178         function hideNewSection ( $value ) {
179                 $this->mHideNewSection = (bool)$value;
180         }
181         function getHideNewSection () {
182                 return (bool)$this->mHideNewSection;
183         }
184         function getNewSection() {
185                 return (bool)$this->mNewSection;
186         }
187
188         function addExternalLink( $url ) {
189                 # We don't register links pointing to our own server, unless... :-)
190                 global $wgServer, $wgRegisterInternalExternals;
191                 if( $wgRegisterInternalExternals or stripos($url,$wgServer.'/')!==0)
192                         $this->mExternalLinks[$url] = 1; 
193         }
194
195         /**
196          * Record a local or interwiki inline link for saving in future link tables.
197          *
198          * @param $title Title object
199          * @param $id Mixed: optional known page_id so we can skip the lookup
200          */
201         function addLink( $title, $id = null ) {
202                 if ( $title->isExternal() ) {
203                         // Don't record interwikis in pagelinks
204                         $this->addInterwikiLink( $title );
205                         return;
206                 }
207                 $ns = $title->getNamespace();
208                 $dbk = $title->getDBkey();
209                 if ( $ns == NS_MEDIA ) {
210                         // Normalize this pseudo-alias if it makes it down here...
211                         $ns = NS_FILE;
212                 } elseif( $ns == NS_SPECIAL ) {
213                         // We don't record Special: links currently
214                         // It might actually be wise to, but we'd need to do some normalization.
215                         return;
216                 } elseif( $dbk === '' ) {
217                         // Don't record self links -  [[#Foo]]
218                         return;
219                 }
220                 if ( !isset( $this->mLinks[$ns] ) ) {
221                         $this->mLinks[$ns] = array();
222                 }
223                 if ( is_null( $id ) ) {
224                         $id = $title->getArticleID();
225                 }
226                 $this->mLinks[$ns][$dbk] = $id;
227         }
228
229         function addImage( $name ) {
230                 $this->mImages[$name] = 1;
231         }
232
233         function addTemplate( $title, $page_id, $rev_id ) {
234                 $ns = $title->getNamespace();
235                 $dbk = $title->getDBkey();
236                 if ( !isset( $this->mTemplates[$ns] ) ) {
237                         $this->mTemplates[$ns] = array();
238                 }
239                 $this->mTemplates[$ns][$dbk] = $page_id;
240                 if ( !isset( $this->mTemplateIds[$ns] ) ) {
241                         $this->mTemplateIds[$ns] = array();
242                 }
243                 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning
244         }
245         
246         /**
247          * @param $title Title object, must be an interwiki link
248          * @throws MWException if given invalid input
249          */
250         function addInterwikiLink( $title ) {
251                 $prefix = $title->getInterwiki();
252                 if( $prefix == '' ) {
253                         throw new MWException( 'Non-interwiki link passed, internal parser error.' );
254                 }
255                 if (!isset($this->mInterwikiLinks[$prefix])) {
256                         $this->mInterwikiLinks[$prefix] = array();
257                 }
258                 $this->mInterwikiLinks[$prefix][$title->getDBkey()] = 1;
259         }
260
261         /**
262          * Add some text to the <head>.
263          * If $tag is set, the section with that tag will only be included once
264          * in a given page.
265          */
266         function addHeadItem( $section, $tag = false ) {
267                 if ( $tag !== false ) {
268                         $this->mHeadItems[$tag] = $section;
269                 } else {
270                         $this->mHeadItems[] = $section;
271                 }
272         }
273         
274         function addModules( $modules ) {
275                 $this->mModules = array_merge( $this->mModules, (array) $modules );
276         }
277
278         /**
279          * Override the title to be used for display
280          * -- this is assumed to have been validated
281          * (check equal normalisation, etc.)
282          *
283          * @param $text String: desired title text
284          */
285         public function setDisplayTitle( $text ) {
286                 $this->setTitleText( $text );
287                 $this->setProperty( 'displaytitle', $text );
288         }
289
290         /**
291          * Get the title to be used for display
292          *
293          * @return String
294          */
295         public function getDisplayTitle() {
296                 $t = $this->getTitleText( );
297                 if( $t === '' ) {
298                         return false;
299                 }
300                 return $t;
301         }
302
303         /**
304          * Fairly generic flag setter thingy.
305          */
306         public function setFlag( $flag ) {
307                 $this->mFlags[$flag] = true;
308         }
309
310         public function getFlag( $flag ) {
311                 return isset( $this->mFlags[$flag] );
312         }
313
314         /**
315          * Set a property to be cached in the DB
316          */
317         public function setProperty( $name, $value ) {
318                 $this->mProperties[$name] = $value;
319         }
320
321         public function getProperty( $name ){
322                 return isset( $this->mProperties[$name] ) ? $this->mProperties[$name] : false;
323         }
324
325         public function getProperties() {
326                 if ( !isset( $this->mProperties ) ) {
327                         $this->mProperties = array();
328                 }
329                 return $this->mProperties;
330         }
331         
332         
333         /**
334          * Returns the options from its ParserOptions which have been taken 
335          * into account to produce this output or false if not available.
336          * @return mixed Array/false
337          */
338          public function getUsedOptions() {
339                 if ( !isset( $this->mAccessedOptions ) ) {
340                         return false;
341                 }
342                 return array_keys( $this->mAccessedOptions );
343          }
344          
345          /**
346           * Callback passed by the Parser to the ParserOptions to keep track of which options are used.
347           * @access private
348           */
349          function recordOption( $option ) {
350                  $this->mAccessedOptions[$option] = true;
351          }
352 }