-
-
Notifications
You must be signed in to change notification settings - Fork 163
/
AopComposerLoader.php
154 lines (131 loc) · 4.28 KB
/
AopComposerLoader.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<?php
declare(strict_types = 1);
/*
* Go! AOP framework
*
* @copyright Copyright 2013, Lisachenko Alexander <lisachenko.it@gmail.com>
*
* This source file is subject to the license that is bundled
* with this source code in the file LICENSE.
*/
namespace Go\Instrument\ClassLoading;
use SplFileInfo;
use Go\Core\AspectContainer;
use Go\Instrument\FileSystem\Enumerator;
use Go\Instrument\PathResolver;
use Go\Instrument\Transformer\FilterInjectorTransformer;
use Composer\Autoload\ClassLoader;
/**
* AopComposerLoader class is responsible to use a weaver for classes instead of original one
*/
class AopComposerLoader
{
/**
* Instance of original autoloader
*/
protected ClassLoader $original;
/**
* AOP kernel options
*/
protected array $options = [];
/**
* File enumerator
*/
protected Enumerator $fileEnumerator;
/**
* Cache state
*/
private array $cacheState;
/**
* Was initialization successful or not
*/
private static bool $wasInitialized = false;
/**
* Constructs an wrapper for the composer loader
*
* @param array $options Configuration options
*/
public function __construct(ClassLoader $original, AspectContainer $container, array $options = [])
{
$this->options = $options;
$this->original = $original;
$prefixes = $original->getPrefixes();
$excludePaths = $options['excludePaths'];
if (!empty($prefixes)) {
// Let's exclude core dependencies from that list
if (isset($prefixes['Dissect'])) {
$excludePaths[] = $prefixes['Dissect'][0];
}
}
$fileEnumerator = new Enumerator($options['appDir'], $options['includePaths'], $excludePaths);
$this->fileEnumerator = $fileEnumerator;
$this->cacheState = $container->getService(CachePathManager::class)->queryCacheState();
}
/**
* Initialize aspect autoloader and returns status whether initialization was successful or not
*
* Replaces original composer autoloader with wrapper
*
* @param array $options Aspect kernel options
*/
public static function init(array $options, AspectContainer $container): bool
{
$loaders = spl_autoload_functions();
foreach ($loaders as &$loader) {
$loaderToUnregister = $loader;
if (is_array($loader) && ($loader[0] instanceof ClassLoader)) {
$loader[0] = new AopComposerLoader($loader[0], $container, $options);
self::$wasInitialized = true;
}
spl_autoload_unregister($loaderToUnregister);
}
unset($loader);
foreach ($loaders as $loader) {
spl_autoload_register($loader);
}
return self::$wasInitialized;
}
/**
* Autoload a class by it's name
*/
public function loadClass(string $class): void
{
$file = $this->findFile($class);
if ($file !== false) {
include $file;
}
}
/**
* Finds either the path to the file where the class is defined,
* or gets the appropriate php://filter stream for the given class.
*
* @return string|false The path/resource if found, false otherwise.
*/
public function findFile(string $class)
{
static $isAllowedFilter = null, $isProduction = false;
if (!$isAllowedFilter) {
$isAllowedFilter = $this->fileEnumerator->getFilter();
$isProduction = !$this->options['debug'];
}
$file = $this->original->findFile($class);
if ($file !== false) {
$file = PathResolver::realpath($file)?:$file;
$cacheState = $this->cacheState[$file] ?? null;
if ($cacheState && $isProduction) {
$file = $cacheState['cacheUri'] ?: $file;
} elseif ($isAllowedFilter(new SplFileInfo($file))) {
// can be optimized here with $cacheState even for debug mode, but no needed right now
$file = FilterInjectorTransformer::rewrite($file);
}
}
return $file;
}
/**
* Whether or not loader was initialized
*/
public static function wasInitialized(): bool
{
return self::$wasInitialized;
}
}