MediaWiki  REL1_20
ResourceLoaderModule.php
Go to the documentation of this file.
00001 <?php
00028 abstract class ResourceLoaderModule {
00029 
00030         # Type of resource
00031         const TYPE_SCRIPTS = 'scripts';
00032         const TYPE_STYLES = 'styles';
00033         const TYPE_MESSAGES = 'messages';
00034         const TYPE_COMBINED = 'combined';
00035 
00036         # sitewide core module like a skin file or jQuery component
00037         const ORIGIN_CORE_SITEWIDE = 1;
00038 
00039         # per-user module generated by the software
00040         const ORIGIN_CORE_INDIVIDUAL = 2;
00041 
00042         # sitewide module generated from user-editable files, like MediaWiki:Common.js, or
00043         # modules accessible to multiple users, such as those generated by the Gadgets extension.
00044         const ORIGIN_USER_SITEWIDE = 3;
00045 
00046         # per-user module generated from user-editable files, like User:Me/vector.js
00047         const ORIGIN_USER_INDIVIDUAL = 4;
00048 
00049         # an access constant; make sure this is kept as the largest number in this group
00050         const ORIGIN_ALL = 10;
00051 
00052         # script and style modules form a hierarchy of trustworthiness, with core modules like
00053         # skins and jQuery as most trustworthy, and user scripts as least trustworthy.  We can
00054         # limit the types of scripts and styles we allow to load on, say, sensitive special
00055         # pages like Special:UserLogin and Special:Preferences
00056         protected $origin = self::ORIGIN_CORE_SITEWIDE;
00057 
00058         /* Protected Members */
00059 
00060         protected $name = null;
00061 
00062         // In-object cache for file dependencies
00063         protected $fileDeps = array();
00064         // In-object cache for message blob mtime
00065         protected $msgBlobMtime = array();
00066 
00067         /* Methods */
00068 
00075         public function getName() {
00076                 return $this->name;
00077         }
00078 
00085         public function setName( $name ) {
00086                 $this->name = $name;
00087         }
00088 
00096         public function getOrigin() {
00097                 return $this->origin;
00098         }
00099 
00106         public function setOrigin( $origin ) {
00107                 $this->origin = $origin;
00108         }
00109 
00114         public function getFlip( $context ) {
00115                 global $wgContLang;
00116 
00117                 return $wgContLang->getDir() !== $context->getDirection();
00118         }
00119 
00127         public function getScript( ResourceLoaderContext $context ) {
00128                 // Stub, override expected
00129                 return '';
00130         }
00131 
00146         public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
00147                 $url = ResourceLoader::makeLoaderURL(
00148                         array( $this->getName() ),
00149                         $context->getLanguage(),
00150                         $context->getSkin(),
00151                         $context->getUser(),
00152                         $context->getVersion(),
00153                         true, // debug
00154                         'scripts', // only
00155                         $context->getRequest()->getBool( 'printable' ),
00156                         $context->getRequest()->getBool( 'handheld' )
00157                 );
00158                 return array( $url );
00159         }
00160 
00167         public function supportsURLLoading() {
00168                 return true;
00169         }
00170 
00179         public function getStyles( ResourceLoaderContext $context ) {
00180                 // Stub, override expected
00181                 return array();
00182         }
00183 
00193         public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
00194                 $url = ResourceLoader::makeLoaderURL(
00195                         array( $this->getName() ),
00196                         $context->getLanguage(),
00197                         $context->getSkin(),
00198                         $context->getUser(),
00199                         $context->getVersion(),
00200                         true, // debug
00201                         'styles', // only
00202                         $context->getRequest()->getBool( 'printable' ),
00203                         $context->getRequest()->getBool( 'handheld' )
00204                 );
00205                 return array( 'all' => array( $url ) );
00206         }
00207 
00215         public function getMessages() {
00216                 // Stub, override expected
00217                 return array();
00218         }
00219 
00225         public function getGroup() {
00226                 // Stub, override expected
00227                 return null;
00228         }
00229 
00235         public function getSource() {
00236                 // Stub, override expected
00237                 return 'local';
00238         }
00239 
00247         public function getPosition() {
00248                 return 'bottom';
00249         }
00250 
00258         public function isRaw() {
00259                 return false;
00260         }
00261 
00267         public function getLoaderScript() {
00268                 // Stub, override expected
00269                 return false;
00270         }
00271 
00287         public function getDependencies() {
00288                 // Stub, override expected
00289                 return array();
00290         }
00291 
00299         public function getFileDependencies( $skin ) {
00300                 // Try in-object cache first
00301                 if ( isset( $this->fileDeps[$skin] ) ) {
00302                         return $this->fileDeps[$skin];
00303                 }
00304 
00305                 $dbr = wfGetDB( DB_SLAVE );
00306                 $deps = $dbr->selectField( 'module_deps', 'md_deps', array(
00307                                 'md_module' => $this->getName(),
00308                                 'md_skin' => $skin,
00309                         ), __METHOD__
00310                 );
00311                 if ( !is_null( $deps ) ) {
00312                         $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true );
00313                 } else {
00314                         $this->fileDeps[$skin] = array();
00315                 }
00316                 return $this->fileDeps[$skin];
00317         }
00318 
00325         public function setFileDependencies( $skin, $deps ) {
00326                 $this->fileDeps[$skin] = $deps;
00327         }
00328 
00335         public function getMsgBlobMtime( $lang ) {
00336                 if ( !isset( $this->msgBlobMtime[$lang] ) ) {
00337                         if ( !count( $this->getMessages() ) )
00338                                 return 0;
00339 
00340                         $dbr = wfGetDB( DB_SLAVE );
00341                         $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array(
00342                                         'mr_resource' => $this->getName(),
00343                                         'mr_lang' => $lang
00344                                 ), __METHOD__
00345                         );
00346                         // If no blob was found, but the module does have messages, that means we need
00347                         // to regenerate it. Return NOW
00348                         if ( $msgBlobMtime === false ) {
00349                                 $msgBlobMtime = wfTimestampNow();
00350                         }
00351                         $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime );
00352                 }
00353                 return $this->msgBlobMtime[$lang];
00354         }
00355 
00362         public function setMsgBlobMtime( $lang, $mtime ) {
00363                 $this->msgBlobMtime[$lang] = $mtime;
00364         }
00365 
00366         /* Abstract Methods */
00367 
00382         public function getModifiedTime( ResourceLoaderContext $context ) {
00383                 // 0 would mean now
00384                 return 1;
00385         }
00386 
00396         public function isKnownEmpty( ResourceLoaderContext $context ) {
00397                 return false;
00398         }
00399 
00400 
00402         private static $jsParser;
00403         private static $parseCacheVersion = 1;
00404 
00413         protected function validateScriptFile( $fileName, $contents ) {
00414                 global $wgResourceLoaderValidateJS;
00415                 if ( $wgResourceLoaderValidateJS ) {
00416                         // Try for cache hit
00417                         // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
00418                         $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
00419                         $cache = wfGetCache( CACHE_ANYTHING );
00420                         $cacheEntry = $cache->get( $key );
00421                         if ( is_string( $cacheEntry ) ) {
00422                                 return $cacheEntry;
00423                         }
00424 
00425                         $parser = self::javaScriptParser();
00426                         try {
00427                                 $parser->parse( $contents, $fileName, 1 );
00428                                 $result = $contents;
00429                         } catch (Exception $e) {
00430                                 // We'll save this to cache to avoid having to validate broken JS over and over...
00431                                 $err = $e->getMessage();
00432                                 $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");";
00433                         }
00434 
00435                         $cache->set( $key, $result );
00436                         return $result;
00437                 } else {
00438                         return $contents;
00439                 }
00440         }
00441 
00445         protected static function javaScriptParser() {
00446                 if ( !self::$jsParser ) {
00447                         self::$jsParser = new JSParser();
00448                 }
00449                 return self::$jsParser;
00450         }
00451 
00452 }