MediaWiki  REL1_19
ResourceLoaderModule.php
Go to the documentation of this file.
00001 <?php
00026 abstract class ResourceLoaderModule {
00027 
00028         # Type of resource
00029         const TYPE_SCRIPTS = 'scripts';
00030         const TYPE_STYLES = 'styles';
00031         const TYPE_MESSAGES = 'messages';
00032         const TYPE_COMBINED = 'combined';
00033 
00034         # sitewide core module like a skin file or jQuery component
00035         const ORIGIN_CORE_SITEWIDE = 1;
00036 
00037         # per-user module generated by the software
00038         const ORIGIN_CORE_INDIVIDUAL = 2;
00039 
00040         # sitewide module generated from user-editable files, like MediaWiki:Common.js, or
00041         # modules accessible to multiple users, such as those generated by the Gadgets extension.
00042         const ORIGIN_USER_SITEWIDE = 3;
00043 
00044         # per-user module generated from user-editable files, like User:Me/vector.js
00045         const ORIGIN_USER_INDIVIDUAL = 4;
00046 
00047         # an access constant; make sure this is kept as the largest number in this group
00048         const ORIGIN_ALL = 10;
00049 
00050         # script and style modules form a hierarchy of trustworthiness, with core modules like
00051         # skins and jQuery as most trustworthy, and user scripts as least trustworthy.  We can
00052         # limit the types of scripts and styles we allow to load on, say, sensitive special
00053         # pages like Special:UserLogin and Special:Preferences
00054         protected $origin = self::ORIGIN_CORE_SITEWIDE;
00055 
00056         /* Protected Members */
00057 
00058         protected $name = null;
00059 
00060         // In-object cache for file dependencies
00061         protected $fileDeps = array();
00062         // In-object cache for message blob mtime
00063         protected $msgBlobMtime = array();
00064 
00065         /* Methods */
00066 
00073         public function getName() {
00074                 return $this->name;
00075         }
00076 
00083         public function setName( $name ) {
00084                 $this->name = $name;
00085         }
00086 
00094         public function getOrigin() {
00095                 return $this->origin;
00096         }
00097 
00104         public function setOrigin( $origin ) {
00105                 $this->origin = $origin;
00106         }
00107 
00112         public function getFlip( $context ) {
00113                 global $wgContLang;
00114 
00115                 return $wgContLang->getDir() !== $context->getDirection();
00116         }
00117 
00125         public function getScript( ResourceLoaderContext $context ) {
00126                 // Stub, override expected
00127                 return '';
00128         }
00129 
00144         public function getScriptURLsForDebug( ResourceLoaderContext $context ) {
00145                 $url = ResourceLoader::makeLoaderURL(
00146                         array( $this->getName() ),
00147                         $context->getLanguage(),
00148                         $context->getSkin(),
00149                         $context->getUser(),
00150                         $context->getVersion(),
00151                         true, // debug
00152                         'scripts', // only
00153                         $context->getRequest()->getBool( 'printable' ),
00154                         $context->getRequest()->getBool( 'handheld' )
00155                 );
00156                 return array( $url );
00157         }
00158 
00165         public function supportsURLLoading() {
00166                 return true;
00167         }
00168 
00175         public function getStyles( ResourceLoaderContext $context ) {
00176                 // Stub, override expected
00177                 return array();
00178         }
00179 
00189         public function getStyleURLsForDebug( ResourceLoaderContext $context ) {
00190                 $url = ResourceLoader::makeLoaderURL(
00191                         array( $this->getName() ),
00192                         $context->getLanguage(),
00193                         $context->getSkin(),
00194                         $context->getUser(),
00195                         $context->getVersion(),
00196                         true, // debug
00197                         'styles', // only
00198                         $context->getRequest()->getBool( 'printable' ),
00199                         $context->getRequest()->getBool( 'handheld' )
00200                 );
00201                 return array( 'all' => array( $url ) );
00202         }
00203 
00211         public function getMessages() {
00212                 // Stub, override expected
00213                 return array();
00214         }
00215 
00221         public function getGroup() {
00222                 // Stub, override expected
00223                 return null;
00224         }
00225 
00231         public function getSource() {
00232                 // Stub, override expected
00233                 return 'local';
00234         }
00235 
00243         public function getPosition() {
00244                 return 'bottom';
00245         }
00246 
00252         public function getLoaderScript() {
00253                 // Stub, override expected
00254                 return false;
00255         }
00256 
00272         public function getDependencies() {
00273                 // Stub, override expected
00274                 return array();
00275         }
00276 
00284         public function getFileDependencies( $skin ) {
00285                 // Try in-object cache first
00286                 if ( isset( $this->fileDeps[$skin] ) ) {
00287                         return $this->fileDeps[$skin];
00288                 }
00289 
00290                 $dbr = wfGetDB( DB_SLAVE );
00291                 $deps = $dbr->selectField( 'module_deps', 'md_deps', array(
00292                                 'md_module' => $this->getName(),
00293                                 'md_skin' => $skin,
00294                         ), __METHOD__
00295                 );
00296                 if ( !is_null( $deps ) ) {
00297                         $this->fileDeps[$skin] = (array) FormatJson::decode( $deps, true );
00298                 } else {
00299                         $this->fileDeps[$skin] = array();
00300                 }
00301                 return $this->fileDeps[$skin];
00302         }
00303 
00310         public function setFileDependencies( $skin, $deps ) {
00311                 $this->fileDeps[$skin] = $deps;
00312         }
00313 
00320         public function getMsgBlobMtime( $lang ) {
00321                 if ( !isset( $this->msgBlobMtime[$lang] ) ) {
00322                         if ( !count( $this->getMessages() ) )
00323                                 return 0;
00324 
00325                         $dbr = wfGetDB( DB_SLAVE );
00326                         $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array(
00327                                         'mr_resource' => $this->getName(),
00328                                         'mr_lang' => $lang
00329                                 ), __METHOD__
00330                         );
00331                         // If no blob was found, but the module does have messages, that means we need
00332                         // to regenerate it. Return NOW
00333                         if ( $msgBlobMtime === false ) {
00334                                 $msgBlobMtime = wfTimestampNow();
00335                         }
00336                         $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime );
00337                 }
00338                 return $this->msgBlobMtime[$lang];
00339         }
00340 
00347         public function setMsgBlobMtime( $lang, $mtime ) {
00348                 $this->msgBlobMtime[$lang] = $mtime;
00349         }
00350 
00351         /* Abstract Methods */
00352 
00367         public function getModifiedTime( ResourceLoaderContext $context ) {
00368                 // 0 would mean now
00369                 return 1;
00370         }
00371 
00381         public function isKnownEmpty( ResourceLoaderContext $context ) {
00382                 return false;
00383         }
00384 
00385 
00387         private static $jsParser;
00388         private static $parseCacheVersion = 1;
00389 
00398         protected function validateScriptFile( $fileName, $contents ) {
00399                 global $wgResourceLoaderValidateJS;
00400                 if ( $wgResourceLoaderValidateJS ) {
00401                         // Try for cache hit
00402                         // Use CACHE_ANYTHING since filtering is very slow compared to DB queries
00403                         $key = wfMemcKey( 'resourceloader', 'jsparse', self::$parseCacheVersion, md5( $contents ) );
00404                         $cache = wfGetCache( CACHE_ANYTHING );
00405                         $cacheEntry = $cache->get( $key );
00406                         if ( is_string( $cacheEntry ) ) {
00407                                 return $cacheEntry;
00408                         }
00409 
00410                         $parser = self::javaScriptParser();
00411                         try {
00412                                 $parser->parse( $contents, $fileName, 1 );
00413                                 $result = $contents;
00414                         } catch (Exception $e) {
00415                                 // We'll save this to cache to avoid having to validate broken JS over and over...
00416                                 $err = $e->getMessage();
00417                                 $result = "throw new Error(" . Xml::encodeJsVar("JavaScript parse error: $err") . ");";
00418                         }
00419 
00420                         $cache->set( $key, $result );
00421                         return $result;
00422                 } else {
00423                         return $contents;
00424                 }
00425         }
00426 
00430         protected static function javaScriptParser() {
00431                 if ( !self::$jsParser ) {
00432                         self::$jsParser = new JSParser();
00433                 }
00434                 return self::$jsParser;
00435         }
00436 
00437 }