Skip to content

Instantly share code, notes, and snippets.

@AndryG
Last active July 30, 2023 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndryG/9325f36a9350f2f7ccdef002c2aa0882 to your computer and use it in GitHub Desktop.
Save AndryG/9325f36a9350f2f7ccdef002c2aa0882 to your computer and use it in GitHub Desktop.
Case insensitive autoload using composer generated classmap
<?php
/**
* Case insensitive autoload using composer generated classmap
*
* see problem:
* - https://github.com/composer/composer/issues/1803
* - https://stackoverflow.com/questions/20235922/how-to-add-case-insensitive-autoloading-using-composer-generated-classmap
*
* 1. Add this class to project. (you can set any namespace)
* 2. Add to composer.json section "scripts"
* "scripts": {
* "post-autoload-dump": ["CaseIgnoreAutoloader::onPostAutoloadDump"]
* }
* 3. run dump-autoload with create classmap
* 4. view vendor/autoload.php (append registration addition autoloader)
* - addition classmap ignore VENDOR dir
* - autoloader not generated when classmap is empty
* - for temporary disable function you can use key 'map-case-ignore' in 'extra' section (default true)
* "extra": {
* "map-case-ignore": true
* }
*
* 5. How to reproduce this as a plugin? Behavioral change is a mystery.
*
* update 09 jul 2022
* Put an additional autoloader in the beginning.
* Now the param "prepend-autoloader" can be used to determine the order in which loaders work.
*
* @author https://gist.github.com/AndryG
* @license MIT
*/
use Composer\Script\Event;
class CaseIgnoreAutoloader {
/**
* @param Event $event
*/
public static function onPostAutoloadDump(Event $event) {
$isActive = $event->getComposer()->getPackage()->getExtra()['map-case-ignore'] ?? true;
$vendorDir = $event->getComposer()->getConfig()->get('vendor-dir');
$camelMapFile = $vendorDir.'/composer/autoload_classmap.php';
$lowMapFile = $vendorDir.'/composer/autoload_classmap_case_ignore.php';
$baseDirNameLen = mb_strlen(dirname($vendorDir)) + 1;
$lowMap = [];
if ($isActive) { // generate low str map
foreach (require $camelMapFile as $k => $v) {
if (0 !== strpos($v, $vendorDir)) { // except vendor
$lowMap[mb_strtolower($k)] = mb_substr($v, $baseDirNameLen);
}
}
$isActive = (bool)$lowMap; // disable of empty low str map
}
if ($isActive) { // modify autoloader.php and save addition classmap
file_put_contents($lowMapFile, sprintf('<?'.'php return %s;', var_export($lowMap, true)));
$anchor = 'require_once __DIR__ . \'/composer/autoload_real.php\';';
$script = <<<'AUTOLOADER'
// insert by CaseIgnoreAutoloader
spl_autoload_register(function($class){
static $lowMap;
$lowMap ??= require(__DIR__.'/composer/autoload_classmap_case_ignore.php');
if($file = $lowMap[mb_strtolower($class)] ?? false){
include(__dir__.'/../'.$file);
return true;
}
return null;
});
AUTOLOADER;
// update autoload.php
$fName = $vendorDir.'/autoload.php';
$content = file_get_contents($fName);
$content = str_replace($anchor, $script.$anchor, $content);
file_put_contents($fName, $content);
}
if (!$isActive) {
unlink($lowMapFile);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment