Completed
Push — master ( 24edef...a0335e )
by Anton
03:49
created

Tokenizer::makeFinder()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 2
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Tokenizer;
10
11
use Spiral\Core\Component;
12
use Spiral\Core\Container\InjectorInterface;
13
use Spiral\Core\Container\SingletonInterface;
14
use Spiral\Core\Exceptions\Container\InjectionException;
15
use Spiral\Core\MemoryInterface;
16
use Spiral\Core\NullMemory;
17
use Spiral\Debug\Traits\BenchmarkTrait;
18
use Spiral\Debug\Traits\LoggerTrait;
19
use Spiral\Files\FileManager;
20
use Spiral\Files\FilesInterface;
21
use Spiral\Tokenizer\Configs\TokenizerConfig;
22
use Spiral\Tokenizer\Reflections\ReflectionFile;
23
use Spiral\Tokenizer\Traits\TokensTrait;
24
use Symfony\Component\Finder\Finder;
25
26
/**
27
 * Default implementation of spiral tokenizer support while and blacklisted directories and etc.
28
 *
29
 * @todo this component have been written long time ago and require facelift
30
 */
31
class Tokenizer extends Component implements SingletonInterface, TokenizerInterface, InjectorInterface
32
{
33
    use LoggerTrait, BenchmarkTrait, TokensTrait;
34
35
    /**
36
     * Memory section.
37
     */
38
    const MEMORY = 'tokenizer';
39
40
    /**
41
     * @var TokenizerConfig
42
     */
43
    protected $config;
44
45
    /**
46
     * @invisible
47
     *
48
     * @var FilesInterface
49
     */
50
    protected $files;
51
52
    /**
53
     * @invisible
54
     *
55
     * @var MemoryInterface
56
     */
57
    protected $memory;
58
59
    /**
60
     * Tokenizer constructor.
61
     *
62
     * @param TokenizerConfig $config
63
     * @param FilesInterface  $files
64
     * @param MemoryInterface $memory
65
     */
66
    public function __construct(
67
        TokenizerConfig $config,
68
        FilesInterface $files = null,
69
        MemoryInterface $memory = null
70
    ) {
71
        $this->config = $config;
72
73
        $this->files = $files ?? new FileManager();
74
        $this->memory = $memory ?? new NullMemory();
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function fileReflection(string $filename): ReflectionFile
81
    {
82
        $fileMD5 = $this->files->md5($filename = $this->files->normalizePath($filename));
83
84
        $reflection = new ReflectionFile(
85
            $filename,
86
            $this->normalizeTokens(token_get_all($this->files->read($filename))),
87
            (array)$this->memory->loadData(self::MEMORY . '.' . $fileMD5)
88
        );
89
90
        //Let's save to cache
91
        $this->memory->saveData(self::MEMORY . '.' . $fileMD5, $reflection->exportSchema());
92
93
        return $reflection;
94
    }
95
96
    /**
97
     * Get pre-configured class locator.
98
     *
99
     * @param array $directories
100
     * @param array $exclude
101
     *
102
     * @return ClassesInterface
103
     */
104
    public function classLocator(
105
        array $directories = [],
106
        array $exclude = []
107
    ): ClassesInterface {
108
        return new ClassLocator($this, $this->makeFinder($directories, $exclude));
109
    }
110
111
    /**
112
     * Get pre-configured invocation locator.
113
     *
114
     * @param array $directories
115
     * @param array $exclude
116
     *
117
     * @return InvocationsInterface
118
     */
119
    public function invocationLocator(
120
        array $directories = [],
121
        array $exclude = []
122
    ): InvocationsInterface {
123
        return new InvocationsLocator($this, $this->makeFinder($directories, $exclude));
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     *
129
     * @throws InjectionException
130
     */
131
    public function createInjection(\ReflectionClass $class, string $context = null)
132
    {
133
        if ($class->isSubclassOf(ClassesInterface::class)) {
134
            return $this->classLocator();
135
        } elseif ($class->isSubclassOf(InvocationsInterface::class)) {
136
            return $this->invocationLocator();
137
        }
138
139
        throw new InjectionException("Unable to create injection for {$class}");
140
    }
141
142
    /**
143
     * @param array $directories
144
     * @param array $exclude
145
     *
146
     * @return Finder
147
     */
148
    private function makeFinder(
149
        array $directories = [],
150
        array $exclude = []
151
    ): Finder {
152
        $finder = new Finder();
153
154
        if (empty($directories)) {
155
            $directories = $this->config->getDirectories();
156
        }
157
158
        if (empty($exclude)) {
159
            $exclude = $this->config->getExcludes();
160
        }
161
162
        return $finder->files()->in($directories)->exclude($exclude)->name('*.php');
163
    }
164
}
165