182 lines
5.5 KiB
PHP
182 lines
5.5 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Laminas\ZendFrameworkBridge;
|
||
|
|
||
|
use ArrayObject;
|
||
|
use Composer\Autoload\ClassLoader;
|
||
|
use RuntimeException;
|
||
|
|
||
|
use function array_values;
|
||
|
use function class_alias;
|
||
|
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;
|
||
|
use function strtr;
|
||
|
use function substr;
|
||
|
use function trait_exists;
|
||
|
|
||
|
/**
|
||
|
* Alias legacy Zend Framework project classes/interfaces/traits to Laminas equivalents.
|
||
|
*/
|
||
|
class Autoloader
|
||
|
{
|
||
|
private const UPSTREAM_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../../..';
|
||
|
private const LOCAL_COMPOSER_VENDOR_DIRECTORY = __DIR__ . '/../vendor';
|
||
|
|
||
|
/**
|
||
|
* Attach autoloaders for managing legacy ZF artifacts.
|
||
|
*
|
||
|
* We attach two autoloaders:
|
||
|
*
|
||
|
* - The first is _prepended_ to handle new classes and add aliases for
|
||
|
* legacy classes. PHP expects any interfaces implemented, classes
|
||
|
* extended, or traits used when declaring class_alias() to exist and/or
|
||
|
* be autoloadable already at the time of declaration. If not, it will
|
||
|
* raise a fatal error. This autoloader helps mitigate errors in such
|
||
|
* situations.
|
||
|
*
|
||
|
* - The second is _appended_ in order to create aliases for legacy
|
||
|
* classes.
|
||
|
*/
|
||
|
public static function load()
|
||
|
{
|
||
|
$loaded = new ArrayObject([]);
|
||
|
$classLoader = self::getClassLoader();
|
||
|
|
||
|
if ($classLoader === null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
spl_autoload_register(self::createPrependAutoloader(
|
||
|
RewriteRules::namespaceReverse(),
|
||
|
$classLoader,
|
||
|
$loaded
|
||
|
), true, true);
|
||
|
|
||
|
spl_autoload_register(self::createAppendAutoloader(
|
||
|
RewriteRules::namespaceRewrite(),
|
||
|
$loaded
|
||
|
));
|
||
|
}
|
||
|
|
||
|
private static function getClassLoader(): ?ClassLoader
|
||
|
{
|
||
|
$composerVendorDirectory = getenv('COMPOSER_VENDOR_DIR');
|
||
|
if (is_string($composerVendorDirectory)) {
|
||
|
return self::getClassLoaderFromVendorDirectory($composerVendorDirectory);
|
||
|
}
|
||
|
|
||
|
return self::getClassLoaderFromVendorDirectory(self::UPSTREAM_COMPOSER_VENDOR_DIRECTORY)
|
||
|
?? self::getClassLoaderFromVendorDirectory(self::LOCAL_COMPOSER_VENDOR_DIRECTORY);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return callable
|
||
|
*/
|
||
|
private static function createPrependAutoloader(array $namespaces, ClassLoader $classLoader, ArrayObject $loaded)
|
||
|
{
|
||
|
/**
|
||
|
* @param string $class Class name to autoload
|
||
|
* @return void
|
||
|
*/
|
||
|
return static function ($class) use ($namespaces, $classLoader, $loaded) {
|
||
|
if (isset($loaded[$class])) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$segments = explode('\\', $class);
|
||
|
|
||
|
$i = 0;
|
||
|
$check = '';
|
||
|
|
||
|
while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) {
|
||
|
$check .= $segments[$i] . '\\';
|
||
|
++$i;
|
||
|
}
|
||
|
|
||
|
if ($check === '') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ($classLoader->loadClass($class)) {
|
||
|
$legacy = $namespaces[$check]
|
||
|
. strtr(substr($class, strlen($check)), [
|
||
|
'ApiTools' => 'Apigility',
|
||
|
'Mezzio' => 'Expressive',
|
||
|
'Laminas' => 'Zend',
|
||
|
]);
|
||
|
class_alias($class, $legacy);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return callable
|
||
|
*/
|
||
|
private static function createAppendAutoloader(array $namespaces, ArrayObject $loaded)
|
||
|
{
|
||
|
/**
|
||
|
* @param string $class Class name to autoload
|
||
|
* @return void
|
||
|
*/
|
||
|
return static function ($class) use ($namespaces, $loaded) {
|
||
|
$segments = explode('\\', $class);
|
||
|
|
||
|
if ($segments[0] === 'ZendService' && isset($segments[1])) {
|
||
|
$segments[0] .= '\\' . $segments[1];
|
||
|
unset($segments[1]);
|
||
|
$segments = array_values($segments);
|
||
|
}
|
||
|
|
||
|
$i = 0;
|
||
|
$check = '';
|
||
|
|
||
|
// We are checking segments of the namespace to match quicker
|
||
|
while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) {
|
||
|
$check .= $segments[$i] . '\\';
|
||
|
++$i;
|
||
|
}
|
||
|
|
||
|
if ($check === '') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$alias = $namespaces[$check]
|
||
|
. strtr(substr($class, strlen($check)), [
|
||
|
'Apigility' => 'ApiTools',
|
||
|
'Expressive' => 'Mezzio',
|
||
|
'Zend' => 'Laminas',
|
||
|
'AbstractZendServer' => 'AbstractZendServer',
|
||
|
'ZendServerDisk' => 'ZendServerDisk',
|
||
|
'ZendServerShm' => 'ZendServerShm',
|
||
|
'ZendMonitor' => 'ZendMonitor',
|
||
|
]);
|
||
|
|
||
|
$loaded[$alias] = true;
|
||
|
if (class_exists($alias) || interface_exists($alias) || trait_exists($alias)) {
|
||
|
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;
|
||
|
}
|
||
|
}
|