1 | <?php |
||||||||||||||
2 | |||||||||||||||
3 | namespace WebStream\Annotation\Reader; |
||||||||||||||
4 | |||||||||||||||
5 | use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader; |
||||||||||||||
6 | use WebStream\Annotation\Base\IAnnotatable; |
||||||||||||||
7 | use WebStream\Annotation\Base\IClass; |
||||||||||||||
8 | use WebStream\Annotation\Base\IExtension; |
||||||||||||||
9 | use WebStream\Annotation\Base\IMethod; |
||||||||||||||
10 | use WebStream\Annotation\Base\IMethods; |
||||||||||||||
11 | use WebStream\Annotation\Base\IProperty; |
||||||||||||||
12 | use WebStream\Annotation\Base\IRead; |
||||||||||||||
13 | use WebStream\Annotation\Reader\Extend\ExtendReader; |
||||||||||||||
14 | use WebStream\Container\Container; |
||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||
15 | use WebStream\DI\Injector; |
||||||||||||||
0 ignored issues
–
show
The type
WebStream\DI\Injector was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||||||||
16 | use WebStream\Exception\Delegate\ExceptionDelegator; |
||||||||||||||
0 ignored issues
–
show
The type
WebStream\Exception\Delegate\ExceptionDelegator was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||||||||
17 | use WebStream\Exception\Extend\AnnotationException; |
||||||||||||||
0 ignored issues
–
show
The type
WebStream\Exception\Extend\AnnotationException was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths ![]() |
|||||||||||||||
18 | |||||||||||||||
19 | /** |
||||||||||||||
20 | * AnnotationReader |
||||||||||||||
21 | * @author Ryuichi TANAKA. |
||||||||||||||
22 | * @since 2014/05/10 |
||||||||||||||
23 | * @version 0.4 |
||||||||||||||
24 | */ |
||||||||||||||
25 | class AnnotationReader |
||||||||||||||
26 | { |
||||||||||||||
27 | use Injector; |
||||||||||||||
28 | |||||||||||||||
29 | /** |
||||||||||||||
30 | * @var IAnnotatable インスタンス |
||||||||||||||
31 | */ |
||||||||||||||
32 | private IAnnotatable $instance; |
||||||||||||||
33 | |||||||||||||||
34 | /** |
||||||||||||||
35 | * @var array<string> 読み込み可能アノテーション情報 |
||||||||||||||
36 | */ |
||||||||||||||
37 | private array $readableMap; |
||||||||||||||
38 | |||||||||||||||
39 | /** |
||||||||||||||
40 | * @var array<ExtendReader> 拡張アノテーションリーダー |
||||||||||||||
41 | */ |
||||||||||||||
42 | private array $extendReaderMap; |
||||||||||||||
43 | |||||||||||||||
44 | /** |
||||||||||||||
45 | * @var array<string> アノテーション情報リスト |
||||||||||||||
46 | */ |
||||||||||||||
47 | private array $annotationInfoList; |
||||||||||||||
48 | |||||||||||||||
49 | /** |
||||||||||||||
50 | * @var array<string> アノテーション情報リスト(拡張リーダー処理済み) |
||||||||||||||
51 | */ |
||||||||||||||
52 | private array $annotationInfoExtendList; |
||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||
53 | |||||||||||||||
54 | /** |
||||||||||||||
55 | * @var ExceptionDelegator 読み込み時の例外 |
||||||||||||||
56 | */ |
||||||||||||||
57 | private ExceptionDelegator $exception; |
||||||||||||||
58 | |||||||||||||||
59 | /** |
||||||||||||||
60 | * @var string アクションメソッド |
||||||||||||||
61 | */ |
||||||||||||||
62 | private string $actionMethod; |
||||||||||||||
63 | |||||||||||||||
64 | /** |
||||||||||||||
65 | * @var Container デフォルト依存コンテナ |
||||||||||||||
66 | */ |
||||||||||||||
67 | private Container $defaultContainer; |
||||||||||||||
68 | |||||||||||||||
69 | /** |
||||||||||||||
70 | * constructor |
||||||||||||||
71 | * @param IAnnotatable $instance |
||||||||||||||
72 | */ |
||||||||||||||
73 | 148 | public function __construct(IAnnotatable $instance) |
|||||||||||||
74 | { |
||||||||||||||
75 | 148 | $this->initialize(); |
|||||||||||||
76 | 148 | $this->instance = $instance; |
|||||||||||||
77 | } |
||||||||||||||
78 | |||||||||||||||
79 | /** |
||||||||||||||
80 | * 初期化処理 |
||||||||||||||
81 | */ |
||||||||||||||
82 | 148 | private function initialize() |
|||||||||||||
83 | { |
||||||||||||||
84 | 148 | $this->readableMap = []; |
|||||||||||||
85 | 148 | $this->extendReaderMap = []; |
|||||||||||||
86 | 148 | $this->annotationInfoList = []; |
|||||||||||||
87 | 148 | $this->defaultContainer = new Container(false); |
|||||||||||||
88 | } |
||||||||||||||
89 | |||||||||||||||
90 | /** |
||||||||||||||
91 | * アノテーション情報リストを返却する |
||||||||||||||
92 | * @return array<mixed> アノテーション情報リスト |
||||||||||||||
93 | * @throws \ReflectionException |
||||||||||||||
94 | */ |
||||||||||||||
95 | 47 | public function getAnnotationInfoList(): array |
|||||||||||||
96 | { |
||||||||||||||
97 | 47 | if (empty($this->extendReaderMap)) { |
|||||||||||||
98 | 23 | return $this->annotationInfoList; |
|||||||||||||
99 | } |
||||||||||||||
100 | |||||||||||||||
101 | 24 | foreach ($this->annotationInfoList as $key => $annotationInfo) { |
|||||||||||||
102 | 24 | if (!array_key_exists($key, $this->extendReaderMap)) { |
|||||||||||||
103 | continue; |
||||||||||||||
104 | } |
||||||||||||||
105 | 24 | $readerClasspath = $this->extendReaderMap[$key]; |
|||||||||||||
106 | 24 | $refClass = new \ReflectionClass($readerClasspath); |
|||||||||||||
107 | 24 | $reader = $refClass->newInstance(); |
|||||||||||||
108 | 24 | $reader->read($annotationInfo); |
|||||||||||||
109 | 24 | $this->annotationInfoList[$key] = $reader->getAnnotationInfo(); |
|||||||||||||
110 | } |
||||||||||||||
111 | |||||||||||||||
112 | 24 | return $this->annotationInfoList; |
|||||||||||||
113 | } |
||||||||||||||
114 | |||||||||||||||
115 | /** |
||||||||||||||
116 | * 発生した例外を返却する |
||||||||||||||
117 | * @return ExceptionDelegator 発生した例外 |
||||||||||||||
118 | */ |
||||||||||||||
119 | 100 | public function getException(): ?ExceptionDelegator |
|||||||||||||
120 | { |
||||||||||||||
121 | 100 | return $this->exception ?? null; |
|||||||||||||
122 | } |
||||||||||||||
123 | |||||||||||||||
124 | /** |
||||||||||||||
125 | * アクションメソッドを設定する |
||||||||||||||
126 | * @param string アクションメソッド |
||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||
127 | */ |
||||||||||||||
128 | 147 | public function setActionMethod(string $actionMethod) |
|||||||||||||
129 | { |
||||||||||||||
130 | 147 | $this->actionMethod = $actionMethod; |
|||||||||||||
131 | } |
||||||||||||||
132 | |||||||||||||||
133 | /** |
||||||||||||||
134 | * 読み込み可能アノテーション情報を設定する |
||||||||||||||
135 | * @param string アノテーションクラスパス |
||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||
136 | * @param Container|null $container |
||||||||||||||
137 | */ |
||||||||||||||
138 | 142 | public function readable(string $classpath, Container $container = null) |
|||||||||||||
139 | { |
||||||||||||||
140 | 142 | $this->readableMap[$classpath] = $container; |
|||||||||||||
141 | } |
||||||||||||||
142 | |||||||||||||||
143 | /** |
||||||||||||||
144 | * 拡張アノテーションリーダーを設定する |
||||||||||||||
145 | * @param string アノテーションクラスパス |
||||||||||||||
0 ignored issues
–
show
|
|||||||||||||||
146 | * @param string 拡張アノテーションリーダークラスパス |
||||||||||||||
147 | */ |
||||||||||||||
148 | 26 | public function useExtendReader(string $annotationClasspath, string $readerClasspath) |
|||||||||||||
149 | { |
||||||||||||||
150 | 26 | $this->extendReaderMap[$annotationClasspath] = $readerClasspath; |
|||||||||||||
151 | } |
||||||||||||||
152 | |||||||||||||||
153 | /** |
||||||||||||||
154 | * アノテーション情報を読み込む |
||||||||||||||
155 | */ |
||||||||||||||
156 | public function read() |
||||||||||||||
157 | { |
||||||||||||||
158 | try { |
||||||||||||||
159 | $this->readClass(); |
||||||||||||||
160 | $this->readMethod(); |
||||||||||||||
161 | $this->readProperty(); |
||||||||||||||
162 | } catch (\Exception $e) { |
||||||||||||||
163 | $this->initialize(); |
||||||||||||||
164 | throw new AnnotationException($e); |
||||||||||||||
165 | } |
||||||||||||||
166 | } |
||||||||||||||
167 | |||||||||||||||
168 | /** |
||||||||||||||
169 | * クラス情報を読み込む |
||||||||||||||
170 | * @throws \ReflectionException |
||||||||||||||
171 | */ |
||||||||||||||
172 | 2 | public function readClass() |
|||||||||||||
173 | { |
||||||||||||||
174 | 2 | $reader = new DoctrineAnnotationReader(); |
|||||||||||||
175 | 2 | $refClass = new \ReflectionClass($this->instance); |
|||||||||||||
176 | |||||||||||||||
177 | 2 | while ($refClass !== false) { |
|||||||||||||
178 | 2 | $annotations = $reader->getClassAnnotations($refClass); |
|||||||||||||
179 | |||||||||||||||
180 | 2 | if (!empty($annotations)) { |
|||||||||||||
181 | 2 | for ($i = 0, $count = count($annotations); $i < $count; $i++) { |
|||||||||||||
182 | 2 | $annotation = $annotations[$i]; |
|||||||||||||
183 | |||||||||||||||
184 | 2 | if (!$annotation instanceof IClass) { |
|||||||||||||
185 | continue; |
||||||||||||||
186 | } |
||||||||||||||
187 | |||||||||||||||
188 | 2 | $key = get_class($annotation); |
|||||||||||||
189 | 2 | $container = null; |
|||||||||||||
190 | 2 | if (!array_key_exists($key, $this->readableMap)) { |
|||||||||||||
191 | if ($annotation instanceof IExtension) { |
||||||||||||||
192 | $container = $this->defaultContainer; |
||||||||||||||
193 | } else { |
||||||||||||||
194 | continue; |
||||||||||||||
195 | } |
||||||||||||||
196 | } else { |
||||||||||||||
197 | 2 | $container = $this->readableMap[$key]; |
|||||||||||||
198 | } |
||||||||||||||
199 | |||||||||||||||
200 | try { |
||||||||||||||
201 | 2 | $annotation->onClassInject($this->instance, $refClass, $container); |
|||||||||||||
202 | 1 | } catch (\Exception $e) { |
|||||||||||||
203 | 1 | if (!isset($this->exception)) { |
|||||||||||||
204 | 1 | $this->exception = new ExceptionDelegator($this->instance, $e); |
|||||||||||||
205 | } |
||||||||||||||
206 | 1 | continue; |
|||||||||||||
207 | } |
||||||||||||||
208 | |||||||||||||||
209 | // IReadを実装している場合、任意のデータを返却する |
||||||||||||||
210 | 1 | if ($annotation instanceof IRead) { |
|||||||||||||
211 | 1 | if (!array_key_exists($key, $this->annotationInfoList)) { |
|||||||||||||
212 | 1 | $this->annotationInfoList[$key] = []; |
|||||||||||||
213 | } |
||||||||||||||
214 | 1 | $this->annotationInfoList[$key][] = $annotation->getAnnotationInfo(); |
|||||||||||||
215 | } |
||||||||||||||
216 | } |
||||||||||||||
217 | } |
||||||||||||||
218 | |||||||||||||||
219 | 2 | $refClass = $refClass->getParentClass(); |
|||||||||||||
220 | } |
||||||||||||||
221 | } |
||||||||||||||
222 | |||||||||||||||
223 | /** |
||||||||||||||
224 | * メソッド情報を読み込む |
||||||||||||||
225 | */ |
||||||||||||||
226 | 146 | public function readMethod() |
|||||||||||||
227 | { |
||||||||||||||
228 | 146 | $reader = new DoctrineAnnotationReader(); |
|||||||||||||
229 | 146 | $refClass = new \ReflectionClass($this->instance); |
|||||||||||||
230 | |||||||||||||||
231 | 146 | while ($refClass !== false) { |
|||||||||||||
232 | 146 | foreach ($refClass->getMethods() as $refMethod) { |
|||||||||||||
233 | 146 | if ($refClass->getName() !== $refMethod->class) { |
|||||||||||||
234 | continue; |
||||||||||||||
235 | } |
||||||||||||||
236 | |||||||||||||||
237 | 146 | $annotations = $reader->getMethodAnnotations($refMethod); |
|||||||||||||
238 | 146 | if (empty($annotations)) { |
|||||||||||||
239 | 25 | continue; |
|||||||||||||
240 | } |
||||||||||||||
241 | |||||||||||||||
242 | 146 | for ($i = 0, $count = count($annotations); $i < $count; $i++) { |
|||||||||||||
243 | 146 | $annotation = $annotations[$i]; |
|||||||||||||
244 | |||||||||||||||
245 | 146 | if (!$annotation instanceof IMethod && !$annotation instanceof IMethods) { |
|||||||||||||
246 | continue; |
||||||||||||||
247 | } |
||||||||||||||
248 | |||||||||||||||
249 | // IMethodを実装している場合、アクションメソッドのアノテーション以外は読み込まない |
||||||||||||||
250 | // PHPのメソッドは大文字小文字を区別しないため、そのまま比較するとルーティング解決結果と実際のメソッド名が合わないケースがある |
||||||||||||||
251 | // PHPの仕様に合わせてメソッド名の文字列比較は小文字に変換してから行う |
||||||||||||||
252 | 146 | if ($annotation instanceof IMethod && strtolower($this->actionMethod) !== strtolower($refMethod->name)) { |
|||||||||||||
253 | 105 | continue; |
|||||||||||||
254 | } |
||||||||||||||
255 | |||||||||||||||
256 | // 読み込み可能なアノテーション以外は読み込まない |
||||||||||||||
257 | 146 | $key = get_class($annotation); |
|||||||||||||
258 | 146 | $container = null; |
|||||||||||||
259 | 146 | if (!array_key_exists($key, $this->readableMap)) { |
|||||||||||||
260 | 6 | if ($annotation instanceof IExtension) { |
|||||||||||||
261 | 1 | $container = $this->defaultContainer; |
|||||||||||||
262 | } else { |
||||||||||||||
263 | 5 | continue; |
|||||||||||||
264 | } |
||||||||||||||
265 | } else { |
||||||||||||||
266 | 140 | $container = $this->readableMap[$key]; |
|||||||||||||
267 | } |
||||||||||||||
268 | |||||||||||||||
269 | try { |
||||||||||||||
270 | 141 | $annotation->onMethodInject($this->instance, $refMethod, $container); |
|||||||||||||
271 | 56 | } catch (\Exception $e) { |
|||||||||||||
272 | 56 | if (!isset($this->exception)) { |
|||||||||||||
273 | 56 | $this->exception = new ExceptionDelegator($this->instance, $e, $this->actionMethod); |
|||||||||||||
274 | } |
||||||||||||||
275 | 56 | continue; |
|||||||||||||
276 | } |
||||||||||||||
277 | |||||||||||||||
278 | // IReadを実装している場合、任意のデータを返却する |
||||||||||||||
279 | 85 | if ($annotation instanceof IRead) { |
|||||||||||||
280 | 41 | if (!array_key_exists($key, $this->annotationInfoList)) { |
|||||||||||||
281 | 41 | $this->annotationInfoList[$key] = []; |
|||||||||||||
282 | } |
||||||||||||||
283 | 41 | $this->annotationInfoList[$key][] = $annotation->getAnnotationInfo(); |
|||||||||||||
284 | } |
||||||||||||||
285 | } |
||||||||||||||
286 | } |
||||||||||||||
287 | |||||||||||||||
288 | 146 | $refClass = $refClass->getParentClass(); |
|||||||||||||
289 | } |
||||||||||||||
290 | } |
||||||||||||||
291 | |||||||||||||||
292 | /** |
||||||||||||||
293 | * プロパティ情報を読み込む |
||||||||||||||
294 | */ |
||||||||||||||
295 | private function readProperty() |
||||||||||||||
296 | { |
||||||||||||||
297 | $reader = new DoctrineAnnotationReader(); |
||||||||||||||
298 | $refClass = $this->refClass; |
||||||||||||||
299 | |||||||||||||||
300 | while ($refClass !== false) { |
||||||||||||||
301 | foreach ($refClass->getProperties() as $refProperty) { |
||||||||||||||
302 | if ($refClass->getName() !== $refProperty->class) { |
||||||||||||||
303 | continue; |
||||||||||||||
304 | } |
||||||||||||||
305 | |||||||||||||||
306 | $annotations = $reader->getPropertyAnnotations($refProperty); |
||||||||||||||
307 | |||||||||||||||
308 | // アノテーション定義がなければ次へ |
||||||||||||||
309 | if (empty($annotations)) { |
||||||||||||||
310 | continue; |
||||||||||||||
311 | } |
||||||||||||||
312 | |||||||||||||||
313 | for ($i = 0, $count = count($annotations); $i < $count; $i++) { |
||||||||||||||
314 | $annotation = $annotations[$i]; |
||||||||||||||
315 | |||||||||||||||
316 | if (!$annotation instanceof IProperty) { |
||||||||||||||
317 | continue; |
||||||||||||||
318 | } |
||||||||||||||
319 | |||||||||||||||
320 | $key = get_class($annotation); |
||||||||||||||
321 | $container = null; |
||||||||||||||
322 | if (!array_key_exists($key, $this->readableMap)) { |
||||||||||||||
323 | if ($annotation instanceof IExtension) { |
||||||||||||||
324 | $container = $this->defaultContainer; |
||||||||||||||
325 | } else { |
||||||||||||||
326 | continue; |
||||||||||||||
327 | } |
||||||||||||||
328 | } else { |
||||||||||||||
329 | $container = $this->readableMap[$key]; |
||||||||||||||
330 | } |
||||||||||||||
331 | |||||||||||||||
332 | try { |
||||||||||||||
333 | $annotation->onPropertyInject($this->instance, $refProperty, $container); |
||||||||||||||
334 | } catch (\Exception $e) { |
||||||||||||||
335 | if (!isset($this->exception)) { |
||||||||||||||
336 | $this->exception = new ExceptionDelegator($this->instance, $e); |
||||||||||||||
337 | } |
||||||||||||||
338 | continue; |
||||||||||||||
339 | } |
||||||||||||||
340 | |||||||||||||||
341 | // IReadを実装している場合、任意のデータを返却する |
||||||||||||||
342 | if ($annotation instanceof IRead) { |
||||||||||||||
343 | if (!array_key_exists($key, $this->annotationInfoList)) { |
||||||||||||||
344 | $this->annotationInfoList[$key] = []; |
||||||||||||||
345 | } |
||||||||||||||
346 | $this->annotationInfoList[$key][] = $annotation->onInjected(); |
||||||||||||||
0 ignored issues
–
show
The method
onInjected() does not exist on WebStream\Annotation\Base\IExtension .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
onInjected() does not exist on WebStream\Annotation\Base\IRead .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
onInjected() does not exist on WebStream\Annotation\Base\IProperty .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||||||
347 | } |
||||||||||||||
348 | } |
||||||||||||||
349 | } |
||||||||||||||
350 | |||||||||||||||
351 | $refClass = $refClass->getParentClass(); |
||||||||||||||
352 | } |
||||||||||||||
353 | } |
||||||||||||||
354 | } |
||||||||||||||
355 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths