Completed
Push — try/custom-autoloader ( bd5514...741938 )
by
unknown
18:30 queued 10:28
created

AutoloadGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Autoloader Generator.
4
 *
5
 * @package Automattic\Jetpack\Autoloader
6
 */
7
8
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_useFound
9
// phpcs:disable PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
10
// phpcs:disable PHPCompatibility.FunctionDeclarations.NewClosure.Found
11
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_namespaceFound
12
// phpcs:disable PHPCompatibility.Keywords.NewKeywords.t_dirFound
13
// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
14
// phpcs:disable WordPress.Files.FileName.NotHyphenatedLowercase
15
// phpcs:disable WordPress.Files.FileName.InvalidClassFileName
16
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_var_export
17
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
18
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fopen
19
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fwrite
20
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
21
// phpcs:disable WordPress.NamingConventions.ValidVariableName.InterpolatedVariableNotSnakeCase
22
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
23
// phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase
24
25
26
namespace Automattic\Jetpack\Autoloader;
27
28
use Composer\Autoload\AutoloadGenerator as BaseGenerator;
29
use Composer\Autoload\ClassMapGenerator;
30
use Composer\Config;
31
use Composer\Installer\InstallationManager;
32
use Composer\IO\IOInterface;
33
use Composer\Package\PackageInterface;
34
use Composer\Repository\InstalledRepositoryInterface;
35
use Composer\Util\Filesystem;
36
37
/**
38
 * Class AutoloadGenerator.
39
 */
40
class AutoloadGenerator extends BaseGenerator {
41
42
	/**
43
	 * Instantiate an AutoloadGenerator object.
44
	 *
45
	 * @param IOInterface $io IO object.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $io not be null|IOInterface?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
46
	 */
47
	public function __construct( IOInterface $io = null ) {
48
		$this->io = $io;
49
	}
50
51
	/**
52
	 * Dump the autoloader.
53
	 *
54
	 * @param Config                       $config Config object.
55
	 * @param InstalledRepositoryInterface $localRepo Installed Reposetories object.
56
	 * @param PackageInterface             $mainPackage Main Package object.
57
	 * @param InstallationManager          $installationManager Manager for installing packages.
58
	 * @param string                       $targetDir Path to the current target directory.
59
	 * @param bool                         $scanPsr0Packages Whether to search for packages. Currently hard coded to always be false.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $scanPsr0Packages not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
60
	 * @param string                       $suffix The autoloader suffix, ignored since we want our autoloader to only be included once.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $suffix not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
61
	 */
62
	public function dump(
63
		Config $config,
64
		InstalledRepositoryInterface $localRepo,
65
		PackageInterface $mainPackage,
66
		InstallationManager $installationManager,
67
		$targetDir,
68
		$scanPsr0Packages = null, // Not used we always optimize.
69
		$suffix = null
70
	) {
71
72
		$filesystem = new Filesystem();
73
		$filesystem->ensureDirectoryExists( $config->get( 'vendor-dir' ) );
74
75
		$basePath   = $filesystem->normalizePath( realpath( getcwd() ) );
76
		$vendorPath = $filesystem->normalizePath( realpath( $config->get( 'vendor-dir' ) ) );
77
		$targetDir  = $vendorPath . '/' . $targetDir;
78
		$filesystem->ensureDirectoryExists( $targetDir );
79
80
		$packageMap = $this->buildPackageMap( $installationManager, $mainPackage, $localRepo->getCanonicalPackages() );
81
		$autoloads  = $this->parseAutoloads( $packageMap, $mainPackage );
82
83
		$classMap = $this->getClassMap( $autoloads, $filesystem, $vendorPath, $basePath );
84
85
		// Generate the files.
86
		file_put_contents( $targetDir . '/autoload_classmap_package.php', $this->getAutoloadPackagesClassmapFile( $classMap ) );
87
		$this->io->writeError( '<info>Generated autoload_classmap_package.php</info>', true );
88
89
		file_put_contents( $vendorPath . '/autoload_packages.php', $this->getAutoloadPackageFile( $suffix ) );
90
		$this->io->writeError( '<info>Generated autoload_packages.php</info>', true );
91
92
	}
93
94
	/**
95
	 * Takes a classMap and returns the array string representation.
96
	 *
97
	 * @param array $classMap Map of all the package classes and paths and versions.
98
	 *
99
	 * @return string
100
	 */
101
	private function classMapToPHPArrayString( array $classMap ) {
102
		$classmapString = ' array( ';
103
		// ksort( $classMap );
104
		foreach ( $classMap as $class => $code ) {
105
			$classmapString .= ' ' . var_export( $class, true ) . ' => ' . $code;
106
		}
107
		$classmapString .= ");\n";
108
		return $classmapString;
109
	}
110
111
	/**
112
	 * This function differs from the composer parseAutoloadsType in that beside returning the path.
113
	 * It also return the path and the version of a package.
114
	 *
115
	 * @param array            $packageMap Map of all the packages.
116
	 * @param string           $type Type of autoloader to use, currently not used, since we only support psr-4.
117
	 * @param PackageInterface $mainPackage Instance of the Package Object.
118
	 *
119
	 * @return array
120
	 */
121
	protected function parseAutoloadsType( array $packageMap, $type, PackageInterface $mainPackage ) {
122
		$autoloads = array();
123
		foreach ( $packageMap as $item ) {
124
			list($package, $installPath) = $item;
125
			$autoload                    = $package->getAutoload();
126
127
			if ( $package === $mainPackage ) {
128
				$autoload = array_merge_recursive( $autoload, $package->getDevAutoload() );
129
			}
130
131
			// Skip packages that are not 'psr-4' since we only support them for now.
132
			if ( ! isset( $autoload['psr-4'] ) || ! is_array( $autoload['psr-4'] ) ) {
133
				continue;
134
			}
135
136
			if ( null !== $package->getTargetDir() && $package !== $mainPackage ) {
137
				$installPath = substr( $installPath, 0, -strlen( '/' . $package->getTargetDir() ) );
138
			}
139
			foreach ( $autoload['psr-4'] as $namespace => $paths ) {
140
				foreach ( (array) $paths as $path ) {
141
					$relativePath              = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
142
					$autoloads[ $namespace ][] = array(
143
						'path'    => $relativePath,
144
						'version' => $package->getVersion(), // Version of the class comes from the package - should we try to parse it?
145
					);
146
				}
147
			}
148
		}
149
		return $autoloads;
150
	}
151
152
	/**
153
	 * Take the autoloads array and return the classMap that contains the path and the version for each namespace.
154
	 *
155
	 * @param array      $autoloads Array of autoload settings defined defined by the packages.
156
	 * @param Filesystem $filesystem Filesystem class instance.
157
	 * @param string     $vendorPath Path to the vendor directory.
158
	 * @param string     $basePath Base Path.
159
	 *
160
	 * @return array $classMap
161
	 */
162
	private function getClassMap( array $autoloads, Filesystem $filesystem, $vendorPath, $basePath ) {
163
		$classMap = array();
164
		$blacklist        = null; // not supported for now.
165
166
		// Scan the PSR-4 directories for class files, and add them to the class map.
167
		foreach ( $autoloads['psr-4'] as $namespace => $packages_info ) {
168
			foreach ( $packages_info as $package ) {
169
				$dir = $filesystem->normalizePath( $filesystem->isAbsolutePath( $package['path'] )
170
					? $package['path']
171
					: $basePath . '/' . $package['path']
172
				);
173
				$map = ClassMapGenerator::createMap( $dir, $blacklist, $this->io, $namespace );
174
175
				foreach ( $map as $class => $path ) {
176
					$classMap[ $class ] = "array( 'path' => " . $this->getPathCode( $filesystem, $basePath, $vendorPath, $path ) . ", 'version'=>'" . $package['version'] . "' ),\n";
177
				}
178
			}
179
		}
180
181
		return $classMap;
182
	}
183
184
	/**
185
	 *
186
	 * @param $classMap
187
	 *
188
	 * @return string
189
	 */
190
	private function getAutoloadPackagesClassmapFile( $classMap ) {
191
192
		return <<<INCLUDE_CLASSMAP
193
<?php
194
195
// This file `autoload_classmap_packages.php` was auto generated by automattic/jetpack-autoloader.
196
197
\$vendorDir = dirname(__DIR__);
198
199
return $classMap
200
201
INCLUDE_CLASSMAP;
202
	}
203
204
	/**
205
	 * Generate the PHP that will be used in the autoload_packages.php files.
206
	 *
207
	 * @param string $suffix  Unique suffix added to the jetpack_enqueue_packages function.
208
	 *
209
	 * @return string
210
	 */
211
	private function getAutoloadPackageFile( $suffix ) {
212
		$sourceLoader   = fopen( __DIR__ . '/autoload.php', 'r' );
213
		$file_contents  = stream_get_contents( $sourceLoader );
214
		$file_contents .= <<<INCLUDE_FILES
215
/**
216
 * Prepare all the classes for autoloading.
217
 */
218
function enqueue_packages_$suffix() {
219
	\$class_map = require_once dirname( __FILE__ ) . '/composer/autoload_classmap_package.php';
220
	foreach ( \$class_map as \$class_name => \$class_info ) {
221
		enqueue_package_class( \$class_name, \$class_info['version'], \$class_info['path'] );
222
	}
223
}
224
225
enqueue_packages_$suffix();
226
		
227
INCLUDE_FILES;
228
229
		return $file_contents;
230
	}
231
}
232