Completed
Push — add/google-calendar-block ( bbd36e...c90e55 )
by
unknown
06:55
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->getAutoloadClassmapPackagesFile( $classMap ) );
87
		$this->io->writeError( '<info>Generated ' . $targetDir . '/autoload_classmap_package.php</info>', true );
88
89
		file_put_contents( $vendorPath . '/autoload_packages.php', $this->getAutoloadPackageFile( $suffix ) );
90
		$this->io->writeError( '<info>Generated ' . $vendorPath . '/autoload_packages.php</info>', true );
91
92
	}
93
94
	/**
95
	 * This function differs from the composer parseAutoloadsType in that beside returning the path.
96
	 * It also return the path and the version of a package.
97
	 *
98
	 * Currently supports only psr-4 and clasmap parsing.
99
	 *
100
	 * @param array            $packageMap Map of all the packages.
101
	 * @param string           $type Type of autoloader to use, currently not used, since we only support psr-4.
102
	 * @param PackageInterface $mainPackage Instance of the Package Object.
103
	 *
104
	 * @return array
105
	 */
106
	protected function parseAutoloadsType( array $packageMap, $type, PackageInterface $mainPackage ) {
107
		$autoloads = array();
108
109
		if ( 'psr-4' !== $type && 'classmap' !== $type ) {
110
			return parent::parseAutoloadsType( $packageMap, $type, $mainPackage );
111
		}
112
113
		foreach ( $packageMap as $item ) {
114
			list($package, $installPath) = $item;
115
			$autoload                    = $package->getAutoload();
116
117
			if ( $package === $mainPackage ) {
118
				$autoload = array_merge_recursive( $autoload, $package->getDevAutoload() );
119
			}
120
121
			if ( null !== $package->getTargetDir() && $package !== $mainPackage ) {
122
				$installPath = substr( $installPath, 0, -strlen( '/' . $package->getTargetDir() ) );
123
			}
124
125 View Code Duplication
			if ( 'psr-4' === $type && isset( $autoload['psr-4'] ) && is_array( $autoload['psr-4'] ) ) {
126
				foreach ( $autoload['psr-4'] as $namespace => $paths ) {
127
					$paths = is_array( $paths ) ? $paths : array( $paths );
128
					foreach ( $paths as $path ) {
129
						$relativePath              = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
130
						$autoloads[ $namespace ][] = array(
131
							'path'    => $relativePath,
132
							'version' => $package->getVersion(), // Version of the class comes from the package - should we try to parse it?
133
						);
134
					}
135
				}
136
			}
137
138 View Code Duplication
			if ( 'classmap' === $type && isset( $autoload['classmap'] ) && is_array( $autoload['classmap'] ) ) {
139
				foreach ( $autoload['classmap'] as $paths ) {
140
					$paths = is_array( $paths ) ? $paths : array( $paths );
141
					foreach ( $paths as $path ) {
142
						$relativePath = empty( $installPath ) ? ( empty( $path ) ? '.' : $path ) : $installPath . '/' . $path;
143
						$autoloads[]  = array(
144
							'path'    => $relativePath,
145
							'version' => $package->getVersion(), // Version of the class comes from the package - should we try to parse it?
146
						);
147
					}
148
				}
149
			}
150
		}
151
152
		return $autoloads;
153
	}
154
155
	/**
156
	 * Take the autoloads array and return the classMap that contains the path and the version for each namespace.
157
	 *
158
	 * @param array      $autoloads Array of autoload settings defined defined by the packages.
159
	 * @param Filesystem $filesystem Filesystem class instance.
160
	 * @param string     $vendorPath Path to the vendor directory.
161
	 * @param string     $basePath Base Path.
162
	 *
163
	 * @return array $classMap
164
	 */
165
	private function getClassMap( array $autoloads, Filesystem $filesystem, $vendorPath, $basePath ) {
166
		$blacklist = null;
167
168
		if ( ! empty( $autoloads['exclude-from-classmap'] ) ) {
169
			$blacklist = '{(' . implode( '|', $autoloads['exclude-from-classmap'] ) . ')}';
170
		}
171
172
		$classmapString = '';
173
174
		// Scan the PSR-4 and classmap directories for class files, and add them to the class map.
175
		foreach ( $autoloads['psr-4'] as $namespace => $packages_info ) {
176
			foreach ( $packages_info as $package ) {
177
				$dir       = $filesystem->normalizePath(
178
					$filesystem->isAbsolutePath( $package['path'] )
179
					? $package['path']
180
					: $basePath . '/' . $package['path']
181
				);
182
				$namespace = empty( $namespace ) ? null : $namespace;
183
				$map       = ClassMapGenerator::createMap( $dir, $blacklist, $this->io, $namespace );
184
185 View Code Duplication
				foreach ( $map as $class => $path ) {
186
					$classCode       = var_export( $class, true );
187
					$pathCode        = $this->getPathCode( $filesystem, $basePath, $vendorPath, $path );
188
					$versionCode     = var_export( $package['version'], true );
189
					$classmapString .= <<<CLASS_CODE
190
	$classCode => array(
191
		'version' => $versionCode,
192
		'path'    => $pathCode
193
	),
194
CLASS_CODE;
195
					$classmapString .= PHP_EOL;
196
				}
197
			}
198
		}
199
200
		foreach ( $autoloads['classmap'] as $package ) {
201
			$dir = $filesystem->normalizePath(
202
				$filesystem->isAbsolutePath( $package['path'] )
203
				? $package['path']
204
				: $basePath . '/' . $package['path']
205
			);
206
			$map = ClassMapGenerator::createMap( $dir, $blacklist, $this->io, null );
207
208 View Code Duplication
			foreach ( $map as $class => $path ) {
209
				$classCode       = var_export( $class, true );
210
				$pathCode        = $this->getPathCode( $filesystem, $basePath, $vendorPath, $path );
211
				$versionCode     = var_export( $package['version'], true );
212
				$classmapString .= <<<CLASS_CODE
213
	$classCode => array(
214
		'version' => $versionCode,
215
		'path'    => $pathCode
216
	),
217
CLASS_CODE;
218
				$classmapString .= PHP_EOL;
219
			}
220
		}
221
222
		return 'array( ' . PHP_EOL . $classmapString . ');' . PHP_EOL;
223
	}
224
225
	/**
226
	 * Generate the PHP that will be used in the autoload_classmap_package.php files.
227
	 *
228
	 * @param srting $classMap class map array string that is to be written out to the file.
229
	 *
230
	 * @return string
231
	 */
232
	private function getAutoloadClassmapPackagesFile( $classMap ) {
233
234
		return <<<INCLUDE_CLASSMAP
235
<?php
236
237
// This file `autoload_classmap_packages.php` was auto generated by automattic/jetpack-autoloader.
238
239
\$vendorDir = dirname(__DIR__);
240
\$baseDir   = dirname(\$vendorDir);
241
242
return $classMap
243
244
INCLUDE_CLASSMAP;
245
	}
246
247
	/**
248
	 * Generate the PHP that will be used in the autoload_packages.php files.
249
	 *
250
	 * @param string $suffix  Unique suffix added to the jetpack_enqueue_packages function.
251
	 *
252
	 * @return string
253
	 */
254
	private function getAutoloadPackageFile( $suffix ) {
255
		$sourceLoader   = fopen( __DIR__ . '/autoload.php', 'r' );
256
		$file_contents  = stream_get_contents( $sourceLoader );
257
		$file_contents .= <<<INCLUDE_FILES
258
/**
259
 * Prepare all the classes for autoloading.
260
 */
261
function enqueue_packages_$suffix() {
262
	\$class_map = require_once dirname( __FILE__ ) . '/composer/autoload_classmap_package.php';
263
	foreach ( \$class_map as \$class_name => \$class_info ) {
264
		enqueue_package_class( \$class_name, \$class_info['version'], \$class_info['path'] );
265
	}
266
267
	\$autoload_file = __DIR__ . '/composer/autoload_files.php';
268
	\$includeFiles = file_exists( \$autoload_file )
269
		? require \$autoload_file
270
		: array();
271
272
	foreach ( \$includeFiles as \$fileIdentifier => \$file ) {
273
		if ( empty( \$GLOBALS['__composer_autoload_files'][ \$fileIdentifier ] ) ) {
274
			require \$file;
275
276
			\$GLOBALS['__composer_autoload_files'][ \$fileIdentifier ] = true;
277
		}
278
	}
279
}
280
enqueue_packages_$suffix();
281
282
INCLUDE_FILES;
283
284
		return $file_contents;
285
	}
286
}
287