Skip to content

Commit

Permalink
bugfix: allow the class loader to be absent
Browse files Browse the repository at this point in the history
With composer 2.2.0, some autoloaders are loaded even before the `vendor/autoload.php` file is dumped.
This leads to installation crashes in some circumstances due to the fact that this component throws a `RuntimeException` in case the autoloader could not be found.

Due to the fact, that this works properly after the autoloader got dumped, we can safely not register the prepend/append autoloader registration for this case.

Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com>
  • Loading branch information
boesing committed Dec 21, 2021
1 parent bf180a3 commit 8f84616
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 18 deletions.
8 changes: 0 additions & 8 deletions psalm-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,10 @@
<MixedArrayOffset occurrences="1">
<code>$loaded[$class]</code>
</MixedArrayOffset>
<MixedInferredReturnType occurrences="1">
<code>ClassLoader</code>
</MixedInferredReturnType>
<MixedOperand occurrences="2">
<code>$namespaces[$check]</code>
<code>$namespaces[$check]</code>
</MixedOperand>
<MixedReturnStatement occurrences="3">
<code>include __DIR__ . '/../../../autoload.php'</code>
<code>include __DIR__ . '/../vendor/autoload.php'</code>
<code>include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'</code>
</MixedReturnStatement>
<PossiblyFalseOperand occurrences="2">
<code>getenv('COMPOSER_VENDOR_DIR')</code>
<code>getenv('COMPOSER_VENDOR_DIR')</code>
Expand Down
39 changes: 29 additions & 10 deletions src/Autoloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ class Autoloader
public static function load()
{
$loaded = new ArrayObject([]);
$classLoader = self::getClassLoader();

if ($classLoader === null) {
return;
}

spl_autoload_register(self::createPrependAutoloader(
RewriteRules::namespaceReverse(),
self::getClassLoader(),
$classLoader,
$loaded
), true, true);

Expand All @@ -54,25 +59,39 @@ public static function load()
));
}

/**
* @return ClassLoader
* @throws RuntimeException
*/
private static function getClassLoader()
private static function getClassLoader(): ?ClassLoader
{
if (getenv('COMPOSER_VENDOR_DIR') && file_exists(getenv('COMPOSER_VENDOR_DIR') . '/autoload.php')) {
return include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php';
/** @psalm-suppress MixedAssignment */
$loader = include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php';
if (!$loader instanceof ClassLoader) {
return null;
}

return $loader;
}

if (file_exists(__DIR__ . '/../../../autoload.php')) {
return include __DIR__ . '/../../../autoload.php';
/** @psalm-suppress MixedAssignment */
$loader = include __DIR__ . '/../../../autoload.php';
if (!$loader instanceof ClassLoader) {
return null;
}

return $loader;
}

if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
return include __DIR__ . '/../vendor/autoload.php';
/** @psalm-suppress MixedAssignment */
$loader = include __DIR__ . '/../vendor/autoload.php';
if (!$loader instanceof ClassLoader) {
return null;
}

return $loader;
}

throw new RuntimeException('Cannot detect composer autoload. Please run composer install');
return null;
}

/**
Expand Down
24 changes: 24 additions & 0 deletions test/AutoloaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
namespace LaminasTest\ZendFrameworkBridge;

use Laminas\LegacyTypeHint;
use Laminas\ZendFrameworkBridge\Autoloader;
use PHPUnit\Framework\TestCase;

use function class_exists;
use function clearstatcache;
use function file_exists;
use function get_class;
use function interface_exists;
use function rename;

class AutoloaderTest extends TestCase
{
private const PATH_TO_AUTOLOADER = __DIR__ . '/../vendor/autoload.php';

/**
* @return array[]
*/
Expand Down Expand Up @@ -139,4 +145,22 @@ public function testReverseAliasCreated($actual, $legacy)
self::assertTrue(class_exists($actual));
self::assertTrue(class_exists($legacy));
}

public function testCanHandleNonExistentAutoloadFile(): void
{
self::assertTrue(file_exists(self::PATH_TO_AUTOLOADER));
$pathToAutoloaderBackup = sprintf('%s.bak', self::PATH_TO_AUTOLOADER);
rename(self::PATH_TO_AUTOLOADER, $pathToAutoloaderBackup);
clearstatcache();
self::assertFalse(file_exists(self::PATH_TO_AUTOLOADER));

try {
Autoloader::load();
} finally {
rename($pathToAutoloaderBackup, self::PATH_TO_AUTOLOADER);
}

clearstatcache();
self::assertTrue(file_exists(self::PATH_TO_AUTOLOADER));
}
}

0 comments on commit 8f84616

Please sign in to comment.