Completed
Push — master ( efe256...811ea7 )
by Alexander
11s
created

AopComposerLoader::wasInitialized()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
declare(strict_types = 1);
3
/*
4
 * Go! AOP framework
5
 *
6
 * @copyright Copyright 2013, Lisachenko Alexander <[email protected]>
7
 *
8
 * This source file is subject to the license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Go\Instrument\ClassLoading;
13
14
use Go\Core\AspectContainer;
15
use Go\Instrument\FileSystem\Enumerator;
16
use Go\Instrument\PathResolver;
17
use Go\Instrument\Transformer\FilterInjectorTransformer;
18
use Composer\Autoload\ClassLoader;
19
use Doctrine\Common\Annotations\AnnotationRegistry;
20
21
/**
22
 * AopComposerLoader class is responsible to use a weaver for classes instead of original one
23
 */
24
class AopComposerLoader
25
{
26
27
    /**
28
     * Instance of original autoloader
29
     */
30
    protected $original;
31
32
    /**
33
     * AOP kernel options
34
     *
35
     * @var array
36
     */
37
    protected $options = [];
38
39
    /**
40
     * File enumerator
41
     */
42
    protected $fileEnumerator;
43
44
    /**
45
     * Cache state
46
     *
47
     * @var array
48
     */
49
    private $cacheState;
50
51
    /**
52
     * Was initialization successful or not
53
     */
54
    private static $wasInitialized = false;
55
56
    /**
57
     * Constructs an wrapper for the composer loader
58
     *
59
     * @param array $options Configuration options
60
     */
61 1
    public function __construct(ClassLoader $original, AspectContainer $container, array $options = [])
62
    {
63 1
        $this->options  = $options;
64 1
        $this->original = $original;
65
66 1
        $prefixes     = $original->getPrefixes();
67 1
        $excludePaths = $options['excludePaths'];
68
69 1
        if (!empty($prefixes)) {
70
            // Let's exclude core dependencies from that list
71 1
            if (isset($prefixes['Dissect'])) {
72 1
                $excludePaths[] = $prefixes['Dissect'][0];
73
            }
74 1
            if (isset($prefixes['Doctrine\\Common\\Annotations\\'])) {
75
                $excludePaths[] = substr($prefixes['Doctrine\\Common\\Annotations\\'][0], 0, -16);
76
            }
77
        }
78
79 1
        $fileEnumerator       = new Enumerator($options['appDir'], $options['includePaths'], $excludePaths);
80 1
        $this->fileEnumerator = $fileEnumerator;
81 1
        $this->cacheState     = $container->get('aspect.cache.path.manager')->queryCacheState();
82 1
    }
83
84
    /**
85
     * Initialize aspect autoloader and returns status whether initialization was successful or not
86
     *
87
     * Replaces original composer autoloader with wrapper
88
     *
89
     * @param array $options Aspect kernel options
90
     */
91 1
    public static function init(array $options, AspectContainer $container): bool
92
    {
93 1
        $loaders = spl_autoload_functions();
94
95 1
        foreach ($loaders as &$loader) {
96 1
            $loaderToUnregister = $loader;
97 1
            if (is_array($loader) && ($loader[0] instanceof ClassLoader)) {
0 ignored issues
show
Bug introduced by
The class Composer\Autoload\ClassLoader does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
98 1
                $originalLoader = $loader[0];
99
                // Configure library loader for doctrine annotation loader
100 1
                AnnotationRegistry::registerLoader(function($class) use ($originalLoader) {
0 ignored issues
show
Deprecated Code introduced by
The method Doctrine\Common\Annotati...istry::registerLoader() has been deprecated with message: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists')

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
101 1
                    $originalLoader->loadClass($class);
102
103 1
                    return class_exists($class, false);
104 1
                });
105 1
                $loader[0] = new AopComposerLoader($loader[0], $container, $options);
106 1
                self::$wasInitialized = true;
107
            }
108 1
            spl_autoload_unregister($loaderToUnregister);
109
        }
110 1
        unset($loader);
111
112 1
        foreach ($loaders as $loader) {
113 1
            spl_autoload_register($loader);
114
        }
115
116 1
        return self::$wasInitialized;
117
    }
118
119
    /**
120
     * Autoload a class by it's name
121
     */
122 18
    public function loadClass(string $class): void
123
    {
124 18
        $file = $this->findFile($class);
125
126 18
        if ($file !== false) {
127 18
            include $file;
128
        }
129 18
    }
130
131
    /**
132
     * Finds either the path to the file where the class is defined,
133
     * or gets the appropriate php://filter stream for the given class.
134
     *
135
     * @return string|false The path/resource if found, false otherwise.
136
     */
137 18
    public function findFile(string $class)
138
    {
139 18
        static $isAllowedFilter = null, $isProduction = false;
140 18
        if (!$isAllowedFilter) {
141 1
            $isAllowedFilter = $this->fileEnumerator->getFilter();
142 1
            $isProduction    = !$this->options['debug'];
143
        }
144
145 18
        $file = $this->original->findFile($class);
146
147 18
        if ($file !== false) {
148 18
            $file = PathResolver::realpath($file)?:$file;
149 18
            $cacheState = $this->cacheState[$file] ?? null;
150 18
            if ($cacheState && $isProduction) {
151
                $file = $cacheState['cacheUri'] ?: $file;
152 18
            } elseif ($isAllowedFilter(new \SplFileInfo($file))) {
153
                // can be optimized here with $cacheState even for debug mode, but no needed right now
154 1
                $file = FilterInjectorTransformer::rewrite($file);
155
            }
156
        }
157
158 18
        return $file;
159
    }
160
161
    /**
162
     * Whether or not loader was initialized
163
     */
164
    public static function wasInitialized(): bool
165
    {
166
        return self::$wasInitialized;
167
    }
168
}
169