[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Abstraction for resource loader modules which pull from wiki pages. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @author Trevor Parscal 22 * @author Roan Kattouw 23 */ 24 25 /** 26 * Abstraction for resource loader modules which pull from wiki pages 27 * 28 * This can only be used for wiki pages in the MediaWiki and User namespaces, 29 * because of its dependence on the functionality of 30 * Title::isCssJsSubpage. 31 */ 32 abstract class ResourceLoaderWikiModule extends ResourceLoaderModule { 33 34 /* Protected Members */ 35 36 # Origin is user-supplied code 37 protected $origin = self::ORIGIN_USER_SITEWIDE; 38 39 // In-object cache for title info 40 protected $titleInfo = array(); 41 42 /* Abstract Protected Methods */ 43 44 /** 45 * Subclasses should return an associative array of resources in the module. 46 * Keys should be the title of a page in the MediaWiki or User namespace. 47 * 48 * Values should be a nested array of options. The supported keys are 'type' and 49 * (CSS only) 'media'. 50 * 51 * For scripts, 'type' should be 'script'. 52 * 53 * For stylesheets, 'type' should be 'style'. 54 * There is an optional media key, the value of which can be the 55 * medium ('screen', 'print', etc.) of the stylesheet. 56 * 57 * @param ResourceLoaderContext $context 58 * @return array 59 */ 60 abstract protected function getPages( ResourceLoaderContext $context ); 61 62 /* Protected Methods */ 63 64 /** 65 * Get the Database object used in getTitleMTimes(). Defaults to the local slave DB 66 * but subclasses may want to override this to return a remote DB object, or to return 67 * null if getTitleMTimes() shouldn't access the DB at all. 68 * 69 * NOTE: This ONLY works for getTitleMTimes() and getModifiedTime(), NOT FOR ANYTHING ELSE. 70 * In particular, it doesn't work for getting the content of JS and CSS pages. That functionality 71 * will use the local DB irrespective of the return value of this method. 72 * 73 * @return DatabaseBase|null 74 */ 75 protected function getDB() { 76 return wfGetDB( DB_SLAVE ); 77 } 78 79 /** 80 * @param Title $title 81 * @return null|string 82 */ 83 protected function getContent( $title ) { 84 if ( !$title->isCssJsSubpage() && !$title->isCssOrJsPage() ) { 85 return null; 86 } 87 $revision = Revision::newFromTitle( $title, false, Revision::READ_NORMAL ); 88 if ( !$revision ) { 89 return null; 90 } 91 92 $content = $revision->getContent( Revision::RAW ); 93 94 if ( !$content ) { 95 wfDebugLog( 'resourceloader', __METHOD__ . ': failed to load content of JS/CSS page!' ); 96 return null; 97 } 98 99 if ( $content->isSupportedFormat( CONTENT_FORMAT_JAVASCRIPT ) ) { 100 return $content->serialize( CONTENT_FORMAT_JAVASCRIPT ); 101 } elseif ( $content->isSupportedFormat( CONTENT_FORMAT_CSS ) ) { 102 return $content->serialize( CONTENT_FORMAT_CSS ); 103 } else { 104 wfDebugLog( 'resourceloader', __METHOD__ . ": bad content model {$content->getModel()} for JS/CSS page!" ); 105 return null; 106 } 107 } 108 109 /* Methods */ 110 111 /** 112 * @param ResourceLoaderContext $context 113 * @return string 114 */ 115 public function getScript( ResourceLoaderContext $context ) { 116 $scripts = ''; 117 foreach ( $this->getPages( $context ) as $titleText => $options ) { 118 if ( $options['type'] !== 'script' ) { 119 continue; 120 } 121 $title = Title::newFromText( $titleText ); 122 if ( !$title || $title->isRedirect() ) { 123 continue; 124 } 125 $script = $this->getContent( $title ); 126 if ( strval( $script ) !== '' ) { 127 $script = $this->validateScriptFile( $titleText, $script ); 128 $scripts .= ResourceLoader::makeComment( $titleText ) . $script . "\n"; 129 } 130 } 131 return $scripts; 132 } 133 134 /** 135 * @param ResourceLoaderContext $context 136 * @return array 137 */ 138 public function getStyles( ResourceLoaderContext $context ) { 139 $styles = array(); 140 foreach ( $this->getPages( $context ) as $titleText => $options ) { 141 if ( $options['type'] !== 'style' ) { 142 continue; 143 } 144 $title = Title::newFromText( $titleText ); 145 if ( !$title || $title->isRedirect() ) { 146 continue; 147 } 148 $media = isset( $options['media'] ) ? $options['media'] : 'all'; 149 $style = $this->getContent( $title ); 150 if ( strval( $style ) === '' ) { 151 continue; 152 } 153 if ( $this->getFlip( $context ) ) { 154 $style = CSSJanus::transform( $style, true, false ); 155 } 156 $style = CSSMin::remap( $style, false, $this->getConfig()->get( 'ScriptPath' ), true ); 157 if ( !isset( $styles[$media] ) ) { 158 $styles[$media] = array(); 159 } 160 $style = ResourceLoader::makeComment( $titleText ) . $style; 161 $styles[$media][] = $style; 162 } 163 return $styles; 164 } 165 166 /** 167 * @param ResourceLoaderContext $context 168 * @return int|mixed 169 */ 170 public function getModifiedTime( ResourceLoaderContext $context ) { 171 $modifiedTime = 1; // wfTimestamp() interprets 0 as "now" 172 $titleInfo = $this->getTitleInfo( $context ); 173 if ( count( $titleInfo ) ) { 174 $mtimes = array_map( function( $value ) { 175 return $value['timestamp']; 176 }, $titleInfo ); 177 $modifiedTime = max( $modifiedTime, max( $mtimes ) ); 178 } 179 $modifiedTime = max( 180 $modifiedTime, 181 $this->getMsgBlobMtime( $context->getLanguage() ), 182 $this->getDefinitionMtime( $context ) 183 ); 184 return $modifiedTime; 185 } 186 187 /** 188 * Get the definition summary for this module. 189 * 190 * @param ResourceLoaderContext $context 191 * @return array 192 */ 193 public function getDefinitionSummary( ResourceLoaderContext $context ) { 194 return array( 195 'class' => get_class( $this ), 196 'pages' => $this->getPages( $context ), 197 ); 198 } 199 200 /** 201 * @param ResourceLoaderContext $context 202 * @return bool 203 */ 204 public function isKnownEmpty( ResourceLoaderContext $context ) { 205 $titleInfo = $this->getTitleInfo( $context ); 206 // Bug 68488: For modules in the "user" group, we should actually 207 // check that the pages are empty (page_len == 0), but for other 208 // groups, just check the pages exist so that we don't end up 209 // caching temporarily-blank pages without the appropriate 210 // <script> or <link> tag. 211 if ( $this->getGroup() !== 'user' ) { 212 return count( $titleInfo ) === 0; 213 } 214 215 foreach ( $titleInfo as $info ) { 216 if ( $info['length'] !== 0 ) { 217 // At least one non-0-lenth page, not empty 218 return false; 219 } 220 } 221 222 // All pages are 0-length, so it's empty 223 return true; 224 } 225 226 /** 227 * Get the modification times of all titles that would be loaded for 228 * a given context. 229 * @param ResourceLoaderContext $context Context object 230 * @return array keyed by page dbkey, with value is an array with 'length' and 'timestamp' 231 * keys, where the timestamp is a unix one 232 */ 233 protected function getTitleInfo( ResourceLoaderContext $context ) { 234 $dbr = $this->getDB(); 235 if ( !$dbr ) { 236 // We're dealing with a subclass that doesn't have a DB 237 return array(); 238 } 239 240 $hash = $context->getHash(); 241 if ( isset( $this->titleInfo[$hash] ) ) { 242 return $this->titleInfo[$hash]; 243 } 244 245 $this->titleInfo[$hash] = array(); 246 $batch = new LinkBatch; 247 foreach ( $this->getPages( $context ) as $titleText => $options ) { 248 $batch->addObj( Title::newFromText( $titleText ) ); 249 } 250 251 if ( !$batch->isEmpty() ) { 252 $res = $dbr->select( 'page', 253 array( 'page_namespace', 'page_title', 'page_touched', 'page_len' ), 254 $batch->constructSet( 'page', $dbr ), 255 __METHOD__ 256 ); 257 foreach ( $res as $row ) { 258 $title = Title::makeTitle( $row->page_namespace, $row->page_title ); 259 $this->titleInfo[$hash][$title->getPrefixedDBkey()] = array( 260 'timestamp' => wfTimestamp( TS_UNIX, $row->page_touched ), 261 'length' => $row->page_len, 262 ); 263 } 264 } 265 return $this->titleInfo[$hash]; 266 } 267 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |