Skip to content

Commit 0de5134

Browse files
committed
feature #163 Get the autoloader class from current registered autoload functions (silvester)
This PR was squashed before being merged into the 1.0-dev branch (closes #163). Discussion ---------- Get the autoloader class from current registered autoload functions If the default folder for vendor is changed the AutloaderUtil class is no more able to find the ClassLoader. Testing the failure can be easily done by changing the **vendor-dir** in composer.json. After adjusting the autoload require in console file, all makers that use AutoloadUtil will fail. Motivation behind this is development with docker. The application is a lot faster on windows and mac if the vendor folder is not a shared folder. Commits ------- bc04e9a Get the autoloader class from current registered autoload functions
2 parents f9df943 + bc04e9a commit 0de5134

File tree

3 files changed

+57
-40
lines changed

3 files changed

+57
-40
lines changed

src/Resources/config/services.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
<argument>%kernel.project_dir%</argument>
1414
</service>
1515

16-
<service id="maker.autoloader_util" class="Symfony\Bundle\MakerBundle\Util\AutoloaderUtil">
17-
<argument>%kernel.project_dir%</argument>
18-
</service>
16+
<service id="maker.autoloader_util" class="Symfony\Bundle\MakerBundle\Util\AutoloaderUtil" />
1917

2018
<service id="maker.event_registry" class="Symfony\Bundle\MakerBundle\EventRegistry">
2119
<argument type="service" id="event_dispatcher" />

src/Util/AutoloaderUtil.php

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\MakerBundle\Util;
1313

1414
use Composer\Autoload\ClassLoader;
15+
use Symfony\Component\Debug\DebugClassLoader;
1516

1617
/**
1718
* @author Ryan Weaver <[email protected]>
@@ -20,13 +21,10 @@
2021
*/
2122
class AutoloaderUtil
2223
{
23-
private static $classLoader;
24-
private $rootDir;
25-
26-
public function __construct(string $rootDir)
27-
{
28-
$this->rootDir = $rootDir;
29-
}
24+
/**
25+
* @var ClassLoader
26+
*/
27+
private $classLoader;
3028

3129
/**
3230
* Returns the relative path to where a new class should live.
@@ -76,16 +74,27 @@ public function getNamespacePrefixForClass(string $className): string
7674

7775
private function getClassLoader(): ClassLoader
7876
{
79-
if (null === self::$classLoader) {
80-
$autoloadPath = $this->rootDir.'/vendor/autoload.php';
81-
82-
if (!file_exists($autoloadPath)) {
83-
throw new \Exception(sprintf('Could not find the autoload file: "%s"', $autoloadPath));
77+
if (null === $this->classLoader) {
78+
$autoloadFunctions = spl_autoload_functions();
79+
foreach ($autoloadFunctions as $autoloader) {
80+
if (is_array($autoloader) && isset($autoloader[0]) && is_object($autoloader[0])) {
81+
if ($autoloader[0] instanceof ClassLoader) {
82+
$this->classLoader = $autoloader[0];
83+
break;
84+
}
85+
if ($autoloader[0] instanceof DebugClassLoader
86+
&& is_array($autoloader[0]->getClassLoader())
87+
&& $autoloader[0]->getClassLoader()[0] instanceof ClassLoader) {
88+
$this->classLoader = $autoloader[0]->getClassLoader()[0];
89+
break;
90+
}
91+
}
92+
}
93+
if (null === $this->classLoader) {
94+
throw new \Exception('Composer ClassLoader not found!');
8495
}
85-
86-
self::$classLoader = require $autoloadPath;
8796
}
8897

89-
return self::$classLoader;
98+
return $this->classLoader;
9099
}
91100
}

tests/Util/AutoloaderUtilTest.php

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
namespace Symfony\Bundle\MakerBundle\Tests\Util;
44

5+
use Composer\Autoload\ClassLoader;
56
use PHPUnit\Framework\TestCase;
67
use Symfony\Bundle\MakerBundle\Util\AutoloaderUtil;
78
use Symfony\Component\Filesystem\Filesystem;
8-
use Symfony\Component\Process\Process;
99

1010
class AutoloaderUtilTest extends TestCase
1111
{
@@ -28,49 +28,59 @@ public static function setupPaths()
2828

2929
public function testGetPathForFutureClass()
3030
{
31+
$classLoader = new ClassLoader();
3132
$composerJson = [
3233
'autoload' => [
3334
'psr-4' => [
34-
'Also\\In\\Src\\' => 'src/SubDir',
35-
'App\\' => 'src/',
36-
'Other\\Namespace\\' => 'lib',
37-
'' => 'fallback_dir',
35+
'Also\\In\\Src\\' => '/src/SubDir',
36+
'App\\' => '/src',
37+
'Other\\Namespace\\' => '/lib',
38+
'' => '/fallback_dir',
3839
],
3940
'psr-0' => [
40-
'Psr0\\Package' => 'lib/other',
41+
'Psr0\\Package' => '/lib/other',
4142
],
4243
],
4344
];
4445

45-
$fs = new Filesystem();
46-
if (!file_exists(self::$currentRootDir)) {
47-
$fs->mkdir(self::$currentRootDir);
46+
foreach ($composerJson['autoload'] as $psr => $dirs) {
47+
foreach ($dirs as $prefix => $path) {
48+
if ($psr == 'psr-4') {
49+
$classLoader->addPsr4($prefix, self::$currentRootDir.$path);
50+
} else {
51+
$classLoader->add($prefix, self::$currentRootDir.$path);
52+
}
53+
}
4854
}
4955

50-
$fs->remove(self::$currentRootDir.'/vendor');
51-
file_put_contents(
52-
self::$currentRootDir.'/composer.json',
53-
json_encode($composerJson, JSON_PRETTY_PRINT)
54-
);
55-
$process = new Process('composer dump-autoload', self::$currentRootDir);
56-
$process->run();
57-
if (!$process->isSuccessful()) {
58-
throw new \Exception('Error running composer dump-autoload: '.$process->getErrorOutput());
59-
}
56+
$reflection = new \ReflectionClass(AutoloaderUtil::class);
57+
$property = $reflection->getProperty('classLoader');
58+
$property->setAccessible(true);
59+
60+
$autoloaderUtil = new AutoloaderUtil();
6061

62+
$property->setValue($autoloaderUtil, $classLoader);
6163

62-
$autoloaderUtil = new AutoloaderUtil(self::$currentRootDir);
6364
foreach ($this->getPathForFutureClassTests() as $className => $expectedPath) {
6465
$this->assertSame(
65-
// the paths will start in vendor/composer and be relative
66-
str_replace('\\', '/', self::$currentRootDir.'/vendor/composer/../../'.$expectedPath),
66+
str_replace('\\', '/', self::$currentRootDir.'/'.$expectedPath),
6767
// normalize slashes for Windows comparison
6868
str_replace('\\', '/', $autoloaderUtil->getPathForFutureClass($className)),
6969
sprintf('class "%s" should have been in path "%s"', $className, $expectedPath)
7070
);
7171
}
7272
}
7373

74+
public function testCanFindClassLoader()
75+
{
76+
$reflection = new \ReflectionClass(AutoloaderUtil::class);
77+
$method = $reflection->getMethod('getClassLoader');
78+
$method->setAccessible(true);
79+
$autoloaderUtil = new AutoloaderUtil();
80+
$autoloader = $method->invoke($autoloaderUtil);
81+
$this->assertInstanceOf(ClassLoader::class, $autoloader, 'Wrong ClassLoader found');
82+
}
83+
7484
public function getPathForFutureClassTests()
7585
{
7686
return [

0 commit comments

Comments
 (0)