Completed
Push — master ( d3ced3...eebf6f )
by Hannes
02:00
created

ClassIterator::getErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * This program is free software. It comes without any warranty, to
4
 * the extent permitted by applicable law. You can redistribute it
5
 * and/or modify it under the terms of the Do What The Fuck You Want
6
 * To Public License, Version 2, as published by Sam Hocevar. See
7
 * http://www.wtfpl.net/ for more details.
8
 */
9
10
namespace hanneskod\classtools\Iterator;
11
12
use IteratorAggregate;
13
use ReflectionClass;
14
use ReflectionException;
15
use Symfony\Component\Finder\Finder;
16
use hanneskod\classtools\Transformer\Writer;
17
use hanneskod\classtools\Transformer\MinimizingWriter;
18
use hanneskod\classtools\Iterator\Filter\CacheFilter;
19
use hanneskod\classtools\Iterator\Filter\NameFilter;
20
use hanneskod\classtools\Iterator\Filter\NamespaceFilter;
21
use hanneskod\classtools\Iterator\Filter\NotFilter;
22
use hanneskod\classtools\Iterator\Filter\TypeFilter;
23
use hanneskod\classtools\Iterator\Filter\WhereFilter;
24
use hanneskod\classtools\Exception\LogicException;
25
use hanneskod\classtools\Loader\ClassLoader;
26
use hanneskod\classtools\Exception\ReaderException;
27
28
/**
29
 * Iterate over classes found in filesystem
30
 *
31
 * @author Hannes Forsgård <[email protected]>
32
 */
33
class ClassIterator implements IteratorAggregate
34
{
35
    /**
36
     * @var SplFileInfo[] Maps names to SplFileInfo objects
37
     */
38
    private $classMap = [];
39
40
    /**
41
     * @var string[] List of reader error messages
42
     */
43
    private $errors = [];
44
45
    /**
46
     * @var ClassLoader Autoloader for found classes
47
     */
48
    private $loader;
49
50
    /**
51
     * Scan filesystem for classes, interfaces and traits
52
     *
53
     * @param Finder $finder
54
     */
55
    public function __construct(Finder $finder)
56
    {
57
        /** @var \Symfony\Component\Finder\SplFileInfo $fileInfo */
58
        foreach ($finder as $fileInfo) {
59
            $fileInfo = new SplFileInfo($fileInfo);
60
            try {
61
                foreach ($fileInfo->getReader()->getDefinitionNames() as $name) {
62
                    $this->classMap[$name] = $fileInfo;
63
                }
64
            } catch (ReaderException $exception) {
65
                $this->errors[] = $exception->getMessage();
66
            }
67
        }
68
    }
69
70
    /**
71
     * Enable garbage collection of the autoloader at destruct
72
     */
73
    public function __destruct()
74
    {
75
        $this->disableAutoloading();
76
    }
77
78
    /**
79
     * Get syntax errors encountered in source
80
     *
81
     * @return string[]
82
     */
83
    public function getErrors()
84
    {
85
        return $this->errors;
86
    }
87
88
    /**
89
     * Get map of classnames to SplFileInfo objects
90
     *
91
     * @return SplFileInfo[]
92
     */
93
    public function getClassMap()
94
    {
95
        return $this->classMap;
96
    }
97
98
    /**
99
     * Enable autoloading for classes found in filesystem
100
     *
101
     * @return ClassIterator instance for chaining
102
     */
103
    public function enableAutoloading()
104
    {
105
        $this->loader = new ClassLoader($this, true);
106
        return $this;
107
    }
108
109
    /**
110
     * Disable autoloading for classes found in filesystem
111
     *
112
     * @return ClassIterator instance for chaining
113
     */
114
    public function disableAutoloading()
115
    {
116
        if (isset($this->loader)) {
117
            $this->loader->unregister();
118
            unset($this->loader);
119
        }
120
        return $this;
121
    }
122
123
    /**
124
     * Iterator yields classnames as keys and ReflectionClass objects as values
125
     *
126
     * @return \Traversable
127
     */
128
    public function getIterator()
129
    {
130
        /** @var SplFileInfo $fileInfo */
131
        foreach ($this->getClassMap() as $name => $fileInfo) {
132
            try {
133
                yield $name => new ReflectionClass($name);
134
            } catch (ReflectionException $e) {
135
                $msg = "Unable to iterate, {$e->getMessage()}, is autoloading enabled?";
136
                throw new LogicException($msg, 0, $e);
137
            }
138
        }
139
    }
140
141
    /**
142
     * Bind filter to iterator
143
     *
144
     * @param  Filter $filter
145
     * @return Filter The bound filter
146
     */
147
    public function filter(Filter $filter)
148
    {
149
        $filter->bindTo($this);
150
        return $filter;
151
    }
152
153
    /**
154
     * Create a new iterator where classes are filtered based on type
155
     *
156
     * @param  string $typename
157
     * @return Filter The created filter
158
     */
159
    public function type($typename)
160
    {
161
        return $this->filter(new TypeFilter($typename));
162
    }
163
164
    /**
165
     * Create a new iterator where classes are filtered based on name
166
     *
167
     * @param  string $pattern Regular expression used when filtering
168
     * @return Filter The created filter
169
     */
170
    public function name($pattern)
171
    {
172
        return $this->filter(new NameFilter($pattern));
173
    }
174
175
    /**
176
     * Create a new iterator where classes are filtered based on namespace
177
     *
178
     * @param  string $namespace Namespace used when filtering
179
     * @return Filter The created filter
180
     */
181
    public function inNamespace($namespace)
182
    {
183
        return $this->filter(new NamespaceFilter($namespace));
184
    }
185
186
    /**
187
     * Create iterator where classes are filtered based on method return value
188
     *
189
     * @param  string $methodName  Name of method
190
     * @param  mixed  $returnValue Expected return value
191
     * @return Filter The created filter
192
     */
193
    public function where($methodName, $returnValue = true)
194
    {
195
        return $this->filter(new WhereFilter($methodName, $returnValue));
196
    }
197
198
    /**
199
     * Negate a filter
200
     *
201
     * @param  Filter $filter
202
     * @return Filter The created filter
203
     */
204
    public function not(Filter $filter)
205
    {
206
        return $this->filter(new NotFilter($filter));
207
    }
208
209
    /**
210
     * Cache iterator
211
     *
212
     * @return Filter The created filter
213
     */
214
    public function cache()
215
    {
216
        return $this->filter(new CacheFilter);
217
    }
218
219
    /**
220
     * Transform found classes
221
     *
222
     * @param  Writer $writer
223
     * @return string
224
     */
225
    public function transform(Writer $writer)
226
    {
227
        $code = '';
228
229
        /** @var SplFileInfo $fileInfo */
230
        foreach ($this->getClassMap() as $name => $fileInfo) {
231
            $code .= $writer->write($fileInfo->getReader()->read($name)) . "\n";
232
        }
233
234
        return "<?php $code";
235
    }
236
237
    /**
238
     * Minimize found classes
239
     *
240
     * @return string
241
     */
242
    public function minimize()
243
    {
244
        return $this->transform(new MinimizingWriter);
245
    }
246
}
247