Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Autoload
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 5
240
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 generate
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 generateClassmap
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
20
 generateFilesAutoloader
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
 generateAutoloadPhp
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Generate an `autoload.php` file in the root of the target directory.
4 *
5 * @see \Composer\Autoload\ClassMapGenerator
6 */
7
8namespace BrianHenryIE\Strauss;
9
10use BrianHenryIE\Strauss\Composer\Extra\StraussConfig;
11use Composer\Autoload\ClassMapGenerator;
12use League\Flysystem\Filesystem;
13use League\Flysystem\Local\LocalFilesystemAdapter;
14
15class Autoload
16{
17
18    /** @var Filesystem */
19    protected $filesystem;
20
21    protected string $workingDir;
22
23    protected StraussConfig $config;
24
25    /**
26     * The files autolaoders of packages that have been copied by Strauss.
27     * Keyed by package path.
28     *
29     * @var array<string, array<string>> $discoveredFilesAutoloaders Array of packagePath => array of relativeFilePaths.
30     */
31    protected array $discoveredFilesAutoloaders;
32
33    /**
34     * Autoload constructor.
35     * @param StraussConfig $config
36     * @param string $workingDir
37     * @param array<string, array<string>> $discoveredFilesAutoloaders
38     */
39    public function __construct(StraussConfig $config, string $workingDir, array $discoveredFilesAutoloaders)
40    {
41        $this->config = $config;
42        $this->workingDir = $workingDir;
43        $this->discoveredFilesAutoloaders = $discoveredFilesAutoloaders;
44
45        $this->filesystem = new Filesystem(new LocalFilesystemAdapter($workingDir));
46    }
47
48    public function generate(): void
49    {
50        // Do not overwrite Composer's autoload.php.
51        // The correct solution is to add "classmap": ["vendor"] to composer.json, then run composer dump-autoload.
52        if ($this->config->getTargetDirectory() === $this->config->getVendorDirectory()) {
53            return;
54        }
55
56        if (! $this->config->isClassmapOutput()) {
57            return;
58        }
59
60        // TODO Don't do this if vendor is the target dir (i.e. in-situ updating).
61
62        $this->generateClassmap();
63
64        $this->generateFilesAutoloader();
65
66        $this->generateAutoloadPhp();
67    }
68
69    /**
70     * Uses Composer's `ClassMapGenerator::createMap()` to scan the directories for classes and generate the map.
71     *
72     * createMap() returns the full local path, so we then replace the root of the path with a variable.
73     *
74     * @see ClassMapGenerator::dump()
75     *
76     */
77    protected function generateClassmap(): void
78    {
79
80        // Hyphen used to match WordPress Coding Standards.
81        $output_filename = "autoload-classmap.php";
82
83        $targetDirectory = getcwd()
84            . DIRECTORY_SEPARATOR
85            . ltrim($this->config->getTargetDirectory(), DIRECTORY_SEPARATOR);
86
87        $dirs = array(
88            $targetDirectory
89        );
90
91        foreach ($dirs as $dir) {
92            if (!is_dir($dir)) {
93                continue;
94            }
95
96            $dirMap = ClassMapGenerator::createMap($dir);
97
98            array_walk(
99                $dirMap,
100                function (&$filepath, $_class) use ($dir) {
101                    $filepath = "\$strauss_src . '"
102                        . DIRECTORY_SEPARATOR
103                        . ltrim(str_replace($dir, '', $filepath), DIRECTORY_SEPARATOR) . "'";
104                }
105            );
106
107            ob_start();
108
109            echo "<?php\n\n";
110            echo "// {$output_filename} @generated by Strauss\n\n";
111            echo "\$strauss_src = dirname(__FILE__);\n\n";
112            echo "return array(\n";
113            foreach ($dirMap as $class => $file) {
114                // Always use `/` in paths.
115                $file = str_replace(DIRECTORY_SEPARATOR, '/', $file);
116                echo "   '{$class}' => {$file},\n";
117            }
118            echo ");";
119
120            file_put_contents($dir . $output_filename, ob_get_clean());
121        }
122    }
123
124    protected function generateFilesAutoloader(): void
125    {
126
127        // Hyphen used to match WordPress Coding Standards.
128        $outputFilename = "autoload-files.php";
129
130        $filesAutoloaders = $this->discoveredFilesAutoloaders;
131
132        if (empty($filesAutoloaders)) {
133            return;
134        }
135
136        $targetDirectory = getcwd()
137            . DIRECTORY_SEPARATOR
138            . ltrim($this->config->getTargetDirectory(), DIRECTORY_SEPARATOR);
139
140//        $dirname = preg_replace('/[^a-z]/i', '', str_replace(getcwd(), '', $targetDirectory));
141
142        ob_start();
143
144        echo "<?php\n\n";
145        echo "// {$outputFilename} @generated by Strauss\n";
146        echo "// @see https://github.com/BrianHenryIE/strauss/\n\n";
147
148        foreach ($filesAutoloaders as $packagePath => $files) {
149            foreach ($files as $file) {
150                $filepath = DIRECTORY_SEPARATOR . $packagePath . DIRECTORY_SEPARATOR . $file;
151                $filePathinfo = pathinfo(__DIR__ . $filepath);
152                if (!isset($filePathinfo['extension']) || 'php' !== $filePathinfo['extension']) {
153                    continue;
154                }
155                // Always use `/` in paths.
156                $filepath = str_replace(DIRECTORY_SEPARATOR, '/', $filepath);
157                echo "require_once __DIR__ . '{$filepath}';\n";
158            }
159        }
160
161        file_put_contents($targetDirectory . $outputFilename, ob_get_clean());
162    }
163
164    protected function generateAutoloadPhp(): void
165    {
166
167        $autoloadPhp = <<<'EOD'
168<?php
169// autoload.php @generated by Strauss
170
171if ( file_exists( __DIR__ . '/autoload-classmap.php' ) ) {
172    $class_map = include __DIR__ . '/autoload-classmap.php';
173    if ( is_array( $class_map ) ) {
174        spl_autoload_register(
175            function ( $classname ) use ( $class_map ) {
176                if ( isset( $class_map[ $classname ] ) && file_exists( $class_map[ $classname ] ) ) {
177                    require_once $class_map[ $classname ];
178                }
179            }
180        );
181    }
182    unset( $class_map, $strauss_src );
183}
184
185if ( file_exists( __DIR__ . '/autoload-files.php' ) ) {
186    require_once __DIR__ . '/autoload-files.php';
187}
188EOD;
189
190        $relativeFilepath = $this->config->getTargetDirectory() . 'autoload.php';
191        $absoluteFilepath = $this->workingDir . $relativeFilepath;
192
193        file_put_contents($absoluteFilepath, $autoloadPhp);
194    }
195}