From 8f8461659416f096c1add3e9b5277b5bd0332720 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
<2189546+boesing@users.noreply.github.com>
Date: Tue, 21 Dec 2021 14:43:15 +0100
Subject: [PATCH 1/2] bugfix: allow the class loader to be absent
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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>
---
psalm-baseline.xml | 8 --------
src/Autoloader.php | 39 +++++++++++++++++++++++++++++----------
test/AutoloaderTest.php | 24 ++++++++++++++++++++++++
3 files changed, 53 insertions(+), 18 deletions(-)
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 4a186e5..c054410 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -31,18 +31,10 @@
$loaded[$class]
-
- ClassLoader
-
$namespaces[$check]
$namespaces[$check]
-
- include __DIR__ . '/../../../autoload.php'
- include __DIR__ . '/../vendor/autoload.php'
- include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'
-
getenv('COMPOSER_VENDOR_DIR')
getenv('COMPOSER_VENDOR_DIR')
diff --git a/src/Autoloader.php b/src/Autoloader.php
index 261bb88..629e07f 100644
--- a/src/Autoloader.php
+++ b/src/Autoloader.php
@@ -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);
@@ -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;
}
/**
diff --git a/test/AutoloaderTest.php b/test/AutoloaderTest.php
index 8292541..ae247d8 100644
--- a/test/AutoloaderTest.php
+++ b/test/AutoloaderTest.php
@@ -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[]
*/
@@ -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));
+ }
}
From e71bcbb8ba8c87f767db25db96e26c6b382d595f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maximilian=20B=C3=B6sing?=
<2189546+boesing@users.noreply.github.com>
Date: Tue, 21 Dec 2021 14:57:52 +0100
Subject: [PATCH 2/2] qa: optimize code for better readability and avoid
multiple `getenv` calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com>
---
psalm-baseline.xml | 10 ---------
src/Autoloader.php | 54 +++++++++++++++++++++-------------------------
2 files changed, 25 insertions(+), 39 deletions(-)
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index c054410..76d61cd 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -12,9 +12,6 @@
$class
$class
-
- include __DIR__ . '/../../../autoload.php'
-
load
@@ -35,13 +32,6 @@
$namespaces[$check]
$namespaces[$check]
-
- getenv('COMPOSER_VENDOR_DIR')
- getenv('COMPOSER_VENDOR_DIR')
-
-
- include getenv('COMPOSER_VENDOR_DIR') . '/autoload.php'
-
diff --git a/src/Autoloader.php b/src/Autoloader.php
index 629e07f..84f9406 100644
--- a/src/Autoloader.php
+++ b/src/Autoloader.php
@@ -11,6 +11,7 @@
use function class_exists;
use function explode;
use function file_exists;
+use function getenv;
use function interface_exists;
use function spl_autoload_register;
use function strlen;
@@ -23,6 +24,9 @@
*/
class Autoloader
{
+ private const UPSTREAM_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../../..';
+ private const LOCAL_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../vendor';
+
/**
* Attach autoloaders for managing legacy ZF artifacts.
*
@@ -61,37 +65,13 @@ public static function load()
private static function getClassLoader(): ?ClassLoader
{
- if (getenv('COMPOSER_VENDOR_DIR') && file_exists(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')) {
- /** @psalm-suppress MixedAssignment */
- $loader = include __DIR__ . '/../../../autoload.php';
- if (!$loader instanceof ClassLoader) {
- return null;
- }
-
- return $loader;
- }
-
- if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
- /** @psalm-suppress MixedAssignment */
- $loader = include __DIR__ . '/../vendor/autoload.php';
- if (!$loader instanceof ClassLoader) {
- return null;
- }
-
- return $loader;
+ $composerVendorDirectory = getenv('COMPOSER_VENDOR_DIR');
+ if (is_string($composerVendorDirectory)) {
+ return self::getClassLoaderFromVendorDirectory($composerVendorDirectory);
}
- return null;
+ return self::getClassLoaderFromVendorDirectory(self::UPSTREAM_COMPOSER_VENDOR_DIRECTORY)
+ ?? self::getClassLoaderFromVendorDirectory(self::LOCAL_COMPOSER_VENDOR_DIRECTORY);
}
/**
@@ -182,4 +162,20 @@ class_alias($alias, $class);
}
};
}
+
+ private static function getClassLoaderFromVendorDirectory(string $composerVendorDirectory): ?ClassLoader
+ {
+ $filename = rtrim($composerVendorDirectory, '/') . '/autoload.php';
+ if (!file_exists($filename)) {
+ return null;
+ }
+
+ /** @psalm-suppress MixedAssignment */
+ $loader = include $filename;
+ if (!$loader instanceof ClassLoader) {
+ return null;
+ }
+
+ return $loader;
+ }
}