Skip to content

Commit 88bf037

Browse files
authored
Merge pull request #90 from boesing/bugfix/handle-not-existing-autoloader
Allow the composer class loader to be absent, for `composer/composer:2.2.0` compatibility
2 parents bf180a3 + e71bcbb commit 88bf037

File tree

3 files changed

+56
-35
lines changed

3 files changed

+56
-35
lines changed

psalm-baseline.xml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
<code>$class</code>
1313
<code>$class</code>
1414
</MissingClosureParamType>
15-
<MissingFile occurrences="1">
16-
<code>include __DIR__ . '/../../../autoload.php'</code>
17-
</MissingFile>
1815
<MissingReturnType occurrences="1">
1916
<code>load</code>
2017
</MissingReturnType>
@@ -31,25 +28,10 @@
3128
<MixedArrayOffset occurrences="1">
3229
<code>$loaded[$class]</code>
3330
</MixedArrayOffset>
34-
<MixedInferredReturnType occurrences="1">
35-
<code>ClassLoader</code>
36-
</MixedInferredReturnType>
3731
<MixedOperand occurrences="2">
3832
<code>$namespaces[$check]</code>
3933
<code>$namespaces[$check]</code>
4034
</MixedOperand>
41-
<MixedReturnStatement occurrences="3">
42-
<code>include __DIR__ . '/../../../autoload.php'</code>
43-
<code>include __DIR__ . '/../vendor/autoload.php'</code>
44-
<code>include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'</code>
45-
</MixedReturnStatement>
46-
<PossiblyFalseOperand occurrences="2">
47-
<code>getenv('COMPOSER_VENDOR_DIR')</code>
48-
<code>getenv('COMPOSER_VENDOR_DIR')</code>
49-
</PossiblyFalseOperand>
50-
<UnresolvableInclude occurrences="1">
51-
<code>include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'</code>
52-
</UnresolvableInclude>
5335
</file>
5436
<file src="src/ConfigPostProcessor.php">
5537
<InvalidArgument occurrences="1">

src/Autoloader.php

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use function class_exists;
1212
use function explode;
1313
use function file_exists;
14+
use function getenv;
1415
use function interface_exists;
1516
use function spl_autoload_register;
1617
use function strlen;
@@ -23,6 +24,9 @@
2324
*/
2425
class Autoloader
2526
{
27+
private const UPSTREAM_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../../..';
28+
private const LOCAL_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../vendor';
29+
2630
/**
2731
* Attach autoloaders for managing legacy ZF artifacts.
2832
*
@@ -41,10 +45,15 @@ class Autoloader
4145
public static function load()
4246
{
4347
$loaded = new ArrayObject([]);
48+
$classLoader = self::getClassLoader();
49+
50+
if ($classLoader === null) {
51+
return;
52+
}
4453

4554
spl_autoload_register(self::createPrependAutoloader(
4655
RewriteRules::namespaceReverse(),
47-
self::getClassLoader(),
56+
$classLoader,
4857
$loaded
4958
), true, true);
5059

@@ -54,25 +63,15 @@ public static function load()
5463
));
5564
}
5665

57-
/**
58-
* @return ClassLoader
59-
* @throws RuntimeException
60-
*/
61-
private static function getClassLoader()
66+
private static function getClassLoader(): ?ClassLoader
6267
{
63-
if (getenv('COMPOSER_VENDOR_DIR') && file_exists(getenv('COMPOSER_VENDOR_DIR') . '/autoload.php')) {
64-
return include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php';
65-
}
66-
67-
if (file_exists(__DIR__ . '/../../../autoload.php')) {
68-
return include __DIR__ . '/../../../autoload.php';
69-
}
70-
71-
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
72-
return include __DIR__ . '/../vendor/autoload.php';
68+
$composerVendorDirectory = getenv('COMPOSER_VENDOR_DIR');
69+
if (is_string($composerVendorDirectory)) {
70+
return self::getClassLoaderFromVendorDirectory($composerVendorDirectory);
7371
}
7472

75-
throw new RuntimeException('Cannot detect composer autoload. Please run composer install');
73+
return self::getClassLoaderFromVendorDirectory(self::UPSTREAM_COMPOSER_VENDOR_DIRECTORY)
74+
?? self::getClassLoaderFromVendorDirectory(self::LOCAL_COMPOSER_VENDOR_DIRECTORY);
7675
}
7776

7877
/**
@@ -163,4 +162,20 @@ class_alias($alias, $class);
163162
}
164163
};
165164
}
165+
166+
private static function getClassLoaderFromVendorDirectory(string $composerVendorDirectory): ?ClassLoader
167+
{
168+
$filename = rtrim($composerVendorDirectory, '/') . '/autoload.php';
169+
if (!file_exists($filename)) {
170+
return null;
171+
}
172+
173+
/** @psalm-suppress MixedAssignment */
174+
$loader = include $filename;
175+
if (!$loader instanceof ClassLoader) {
176+
return null;
177+
}
178+
179+
return $loader;
180+
}
166181
}

test/AutoloaderTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
namespace LaminasTest\ZendFrameworkBridge;
44

55
use Laminas\LegacyTypeHint;
6+
use Laminas\ZendFrameworkBridge\Autoloader;
67
use PHPUnit\Framework\TestCase;
78

89
use function class_exists;
10+
use function clearstatcache;
11+
use function file_exists;
912
use function get_class;
1013
use function interface_exists;
14+
use function rename;
1115

1216
class AutoloaderTest extends TestCase
1317
{
18+
private const PATH_TO_AUTOLOADER = __DIR__ . '/../vendor/autoload.php';
19+
1420
/**
1521
* @return array[]
1622
*/
@@ -139,4 +145,22 @@ public function testReverseAliasCreated($actual, $legacy)
139145
self::assertTrue(class_exists($actual));
140146
self::assertTrue(class_exists($legacy));
141147
}
148+
149+
public function testCanHandleNonExistentAutoloadFile(): void
150+
{
151+
self::assertTrue(file_exists(self::PATH_TO_AUTOLOADER));
152+
$pathToAutoloaderBackup = sprintf('%s.bak', self::PATH_TO_AUTOLOADER);
153+
rename(self::PATH_TO_AUTOLOADER, $pathToAutoloaderBackup);
154+
clearstatcache();
155+
self::assertFalse(file_exists(self::PATH_TO_AUTOLOADER));
156+
157+
try {
158+
Autoloader::load();
159+
} finally {
160+
rename($pathToAutoloaderBackup, self::PATH_TO_AUTOLOADER);
161+
}
162+
163+
clearstatcache();
164+
self::assertTrue(file_exists(self::PATH_TO_AUTOLOADER));
165+
}
142166
}

0 commit comments

Comments
 (0)