'MediaWiki\\Languages\\Data\\CrhExceptions' => __DIR__ . '/languages/data/CrhExceptions.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php',
'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php',
- 'MediaWiki\\Linker\\LinkRenderer' => __DIR__ . '/includes/linker/LinkRenderer.php',
- 'MediaWiki\\Linker\\LinkRendererFactory' => __DIR__ . '/includes/linker/LinkRendererFactory.php',
- 'MediaWiki\\Linker\\LinkTarget' => __DIR__ . '/includes/linker/LinkTarget.php',
'MediaWiki\\Logger\\ConsoleLogger' => __DIR__ . '/includes/debug/logger/ConsoleLogger.php',
'MediaWiki\\Logger\\ConsoleSpi' => __DIR__ . '/includes/debug/logger/ConsoleSpi.php',
'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php',
"type": "object",
"description": "SpecialPages implemented in this extension (mapping of page name to class name)"
},
+ "AutoloadNamespaces": {
+ "type": "object",
+ "description": "Mapping of PSR-4 compliant namespace to directory for autoloading"
+ },
"AutoloadClasses": {
"type": "object"
},
"type": "object",
"description": "SpecialPages implemented in this extension (mapping of page name to class name)"
},
+ "AutoloadNamespaces": {
+ "type": "object",
+ "description": "Mapping of PSR-4 compliant namespace to directory for autoloading"
+ },
"AutoloadClasses": {
"type": "object"
},
class AutoLoader {
static protected $autoloadLocalClassesLower = null;
+ /**
+ * @private Only public for ExtensionRegistry
+ * @var string[] Namespace (ends with \) => Path (ends with /)
+ */
+ static public $psr4Namespaces = [];
+
/**
* autoload - take a class name and attempt to load it
*
}
}
+ if ( !$filename && strpos( $className, '\\' ) !== false ) {
+ // This class is namespaced, so try looking at the namespace map
+ $prefix = $className;
+ while ( false !== $pos = strrpos( $prefix, '\\' ) ) {
+ // Check to see if this namespace prefix is in the map
+ $prefix = substr( $className, 0, $pos + 1 );
+ if ( isset( self::$psr4Namespaces[$prefix] ) ) {
+ $relativeClass = substr( $className, $pos + 1 );
+ // Build the expected filename, and see if it exists
+ $file = self::$psr4Namespaces[$prefix] .
+ str_replace( '\\', '/', $relativeClass ) . '.php';
+ if ( file_exists( $file ) ) {
+ $filename = $file;
+ break;
+ }
+ }
+
+ // Remove trailing separator for next iteration
+ $prefix = rtrim( $prefix, '\\' );
+ }
+ }
+
if ( !$filename ) {
// Class not found; let the next autoloader try to find it
return;
static function resetAutoloadLocalClassesLower() {
self::$autoloadLocalClassesLower = null;
}
+
+ /**
+ * Get a mapping of namespace => file path
+ * The namespaces should follow the PSR-4 standard for autoloading
+ *
+ * @see <http://www.php-fig.org/psr/psr-4/>
+ * @private Only public for usage in AutoloadGenerator
+ * @since 1.31
+ * @return string[]
+ */
+ public static function getAutoloadNamespaces() {
+ return [
+ 'MediaWiki\\Linker\\' => __DIR__ .'/linker/'
+ ];
+ }
}
+Autoloader::$psr4Namespaces = AutoLoader::getAutoloadNamespaces();
spl_autoload_register( [ 'AutoLoader', 'autoload' ] );
public function readFromQueue( array $queue ) {
global $wgVersion;
$autoloadClasses = [];
+ $autoloadNamespaces = [];
$autoloaderPaths = [];
$processor = new ExtensionProcessor();
$versionChecker = new VersionChecker( $wgVersion );
$incompatible[] = "$path: unsupported manifest_version: {$version}";
}
- $autoload = $this->processAutoLoader( dirname( $path ), $info );
- // Set up the autoloader now so custom processors will work
- $GLOBALS['wgAutoloadClasses'] += $autoload;
- $autoloadClasses += $autoload;
+ $dir = dirname( $path );
+ if ( isset( $info['AutoloadClasses'] ) ) {
+ $autoload = $this->processAutoLoader( $dir, $info['AutoloadClasses'] );
+ $GLOBALS['wgAutoloadClasses'] += $autoload;
+ $autoloadClasses += $autoload;
+ }
+ if ( isset( $info['AutoloadNamespaces'] ) ) {
+ $autoloadNamespaces += $this->processAutoLoader( $dir, $info['AutoloadNamespaces'] );
+ }
// get all requirements/dependencies for this extension
$requires = $processor->getRequirements( $info );
// Get extra paths for later inclusion
$autoloaderPaths = array_merge( $autoloaderPaths,
- $processor->getExtraAutoloaderPaths( dirname( $path ), $info ) );
+ $processor->getExtraAutoloaderPaths( $dir, $info ) );
// Compatible, read and extract info
$processor->extractInfo( $path, $info, $version );
}
$data['globals']['wgAutoloadClasses'] = [];
$data['autoload'] = $autoloadClasses;
$data['autoloaderPaths'] = $autoloaderPaths;
+ $data['autoloaderNS'] = $autoloadNamespaces;
return $data;
}
}
}
+ if ( isset( $info['autoloaderNS'] ) ) {
+ Autoloader::$psr4Namespaces += $info['autoloaderNS'];
+ }
+
foreach ( $info['defines'] as $name => $val ) {
define( $name, $val );
}
}
/**
- * Register classes with the autoloader
+ * Fully expand autoloader paths
*
* @param string $dir
* @param array $info
* @return array
*/
protected function processAutoLoader( $dir, array $info ) {
- if ( isset( $info['AutoloadClasses'] ) ) {
- // Make paths absolute, relative to the JSON file
- return array_map( function ( $file ) use ( $dir ) {
- return "$dir/$file";
- }, $info['AutoloadClasses'] );
- } else {
- return [];
- }
+ // Make paths absolute, relative to the JSON file
+ return array_map( function ( $file ) use ( $dir ) {
+ return "$dir/$file";
+ }, $info );
}
}
*/
protected $overrides = [];
+ /**
+ * Directories that should be excluded
+ *
+ * @var string[]
+ */
+ protected $excludePaths = [];
+
/**
* @param string $basepath Root path of the project being scanned for classes
* @param array|string $flags
}
}
+ /**
+ * Directories that should be excluded
+ *
+ * @since 1.31
+ * @param string[] $paths
+ */
+ public function setExcludePaths( array $paths ) {
+ $this->excludePaths = $paths;
+ }
+
+ /**
+ * Whether the file should be excluded
+ *
+ * @param string $path File path
+ * @return bool
+ */
+ private function shouldExclude( $path ) {
+ foreach ( $this->excludePaths as $dir ) {
+ if ( strpos( $path, $dir ) === 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Force a class to be autoloaded from a specific path, regardless of where
* or if it was detected.
if ( substr( $inputPath, 0, $len ) !== $this->basepath ) {
throw new \Exception( "Path is not within basepath: $inputPath" );
}
+ if ( $this->shouldExclude( $inputPath ) ) {
+ return;
+ }
$result = $this->collector->getClasses(
file_get_contents( $inputPath )
);
die( "This script can only be run from the command line.\n" );
}
+require_once __DIR__ . '/../includes/AutoLoader.php';
require_once __DIR__ . '/../includes/utils/AutoloadGenerator.php';
// Mediawiki installation directory
$base = dirname( __DIR__ );
$generator = new AutoloadGenerator( $base, 'local' );
+$generator->setExcludePaths( array_values( AutoLoader::getAutoloadNamespaces() ) );
$generator->initMediaWikiDefault();
// Write out the autoload
$path = realpath( __DIR__ . '/../../..' );
$oldAutoload = file_get_contents( $path . '/autoload.php' );
$generator = new AutoloadGenerator( $path, 'local' );
+ $generator->setExcludePaths( array_values( AutoLoader::getAutoloadNamespaces() ) );
$generator->initMediaWikiDefault();
$newAutoload = $generator->getAutoload( 'maintenance/generateLocalAutoload.php' );