[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/resourceloader/ -> ResourceLoaderWikiModule.php (source)

   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  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1