*/
protected $hasGeneratedStyles = false;
- /**
- * @var array Cache for mtime
- * @par Usage:
- * @code
- * array( [hash] => [mtime], [hash] => [mtime], ... )
- * @endcode
- */
- protected $modifiedTime = array();
-
/**
* @var array Place where readStyleFile() tracks file dependencies
* @par Usage:
* to $wgResourceBasePath
*
* Below is a description for the $options array:
- * @throws MWException
+ * @throws InvalidArgumentException
* @par Construction options:
* @code
* array(
case 'skinScripts':
case 'skinStyles':
if ( !is_array( $option ) ) {
- throw new MWException(
+ throw new InvalidArgumentException(
"Invalid collated file path list error. " .
"'$option' given, array expected."
);
}
foreach ( $option as $key => $value ) {
if ( !is_string( $key ) ) {
- throw new MWException(
+ throw new InvalidArgumentException(
"Invalid collated file path list key error. " .
"'$key' given, string expected."
);
$this->{$member} = $option;
break;
// Single strings
- case 'group':
case 'position':
+ $this->isPositionDefined = true;
+ case 'group':
case 'skipFunction':
$this->{$member} = (string)$option;
break;
}
if ( $hasTemplates ) {
$this->dependencies[] = 'mediawiki.template';
+ // Ensure relevant template compiler module gets loaded
+ foreach ( $this->templates as $alias => $templatePath ) {
+ if ( is_int( $alias ) ) {
+ $alias = $templatePath;
+ }
+ $suffix = explode( '.', $alias );
+ $suffix = end( $suffix );
+ $compilerModule = 'mediawiki.template.' . $suffix;
+ if ( $suffix !== 'html' && !in_array( $compilerModule, $this->dependencies ) ) {
+ $this->dependencies[] = $compilerModule;
+ }
+ }
}
}
}
/**
- * Get the last modified timestamp of this module.
+ * Helper method to gather file mtimes for getDefinitionSummary.
*
* Last modified timestamps are calculated from the highest last modified
* timestamp of this module's constituent files as well as the files it
* calculations on files relevant to the given language, skin and debug
* mode.
*
- * @param ResourceLoaderContext $context Context in which to calculate
- * the modified time
- * @return int UNIX timestamp
* @see ResourceLoaderModule::getFileDependencies
+ * @param ResourceLoaderContext $context
+ * @return array
*/
- public function getModifiedTime( ResourceLoaderContext $context ) {
- if ( isset( $this->modifiedTime[$context->getHash()] ) ) {
- return $this->modifiedTime[$context->getHash()];
- }
-
+ protected function getFileMtimes( ResourceLoaderContext $context ) {
$files = array();
// Flatten style files into $files
$files = array_map( array( $this, 'getLocalPath' ), $files );
// File deps need to be treated separately because they're already prefixed
$files = array_merge( $files, $this->getFileDependencies( $context->getSkin() ) );
+ // Filter out any duplicates from getFileDependencies() and others.
+ // Most commonly introduced by compileLessFile(), which always includes the
+ // entry point Less file we already know about.
+ $files = array_values( array_unique( $files ) );
- // If a module is nothing but a list of dependencies, we need to avoid
- // giving max() an empty array
- if ( count( $files ) === 0 ) {
- $this->modifiedTime[$context->getHash()] = 1;
- return $this->modifiedTime[$context->getHash()];
- }
-
- $filesMtime = max( array_map( array( __CLASS__, 'safeFilemtime' ), $files ) );
-
- $this->modifiedTime[$context->getHash()] = max(
- $filesMtime,
- $this->getMsgBlobMtime( $context->getLanguage() ),
- $this->getDefinitionMtime( $context )
- );
-
- return $this->modifiedTime[$context->getHash()];
+ // Don't max() because older files are significant.
+ // While the associated file names are significant, that is already taken care of by the
+ // definition summary. Avoid creating an array keyed by file path here because those are
+ // absolute file paths. Including that would needlessly cause global cache invalidation
+ // when the MediaWiki installation path changes (which is quite common in cases like
+ // Wikimedia where the installation path reflects the MediaWiki branch name).
+ return array_map( array( __CLASS__, 'safeFilemtime' ), $files );
}
/**
*/
public function getDefinitionSummary( ResourceLoaderContext $context ) {
$summary = parent::getDefinitionSummary( $context );
+
+ $options = array();
foreach ( array(
'scripts',
'debugScripts',
'group',
'position',
'skipFunction',
+ // FIXME: localBasePath includes the MediaWiki installation path and
+ // needlessly causes cache invalidation.
'localBasePath',
'remoteBasePath',
'debugRaw',
'raw',
) as $member ) {
- $summary[$member] = $this->{$member};
+ $options[$member] = $this->{$member};
};
+
+ $summary[] = array(
+ 'options' => $options,
+ 'fileMtimes' => $this->getFileMTimes( $context ),
+ 'msgBlobMtime' => $this->getMsgBlobMtime( $context->getLanguage() ),
+ );
return $summary;
}
- /* Protected Methods */
-
/**
* @param string|ResourceLoaderFilePath $path
* @return string