Passed
Push — feature/0.7.0 ( 0c7d59...ae5b22 )
by Ryuichi
78:01 queued 33:04
created

CoreExecuteDelegator   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 444
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 444
rs 3.8461
c 0
b 0
f 0
wmc 62

12 Methods

Rating   Name   Duplication   Size   Complexity  
C controllerInjector() 0 96 11
B viewInjector() 0 26 4
C getOriginMethod() 0 27 7
C run() 0 47 15
A getInstance() 0 3 2
A __call() 0 3 1
B modelInjector() 0 41 6
A execute() 0 9 3
B helperInjector() 0 37 6
B serviceInjector() 0 36 5
A __get() 0 3 1
A __construct() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like CoreExecuteDelegator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CoreExecuteDelegator, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace WebStream\Delegate;
3
4
use WebStream\Core\CoreInterface;
5
use WebStream\Core\CoreController;
6
use WebStream\Core\CoreService;
7
use WebStream\Core\CoreModel;
8
use WebStream\Core\CoreView;
9
use WebStream\Core\CoreHelper;
10
use WebStream\Cache\Driver\CacheDriverFactory;
11
use WebStream\Module\Utility\CommonUtils;
12
use WebStream\Container\Container;
13
use WebStream\Exception\ApplicationException;
14
use WebStream\Exception\SystemException;
15
use WebStream\Exception\DelegateException;
16
use WebStream\Exception\Extend\AnnotationException;
17
use WebStream\Exception\Extend\MethodNotFoundException;
18
use Doctrine\Common\Annotations\AnnotationException as DoctrineAnnotationException;
0 ignored issues
show
Bug introduced by
The type Doctrine\Common\Annotations\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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
20
/**
21
 * CoreExecuteDelegator
22
 * @author Ryuichi TANAKA.
23
 * @since 2015/02/25
24
 * @version 0.4
25
 */
26
class CoreExecuteDelegator
27
{
28
    use CommonUtils;
29
30
    /**
31
     * @var CoreInterface インスタンス
32
     */
33
    private $instance;
34
35
    /**
36
     * @var CoreInterface 注入済みインスタンス
37
     */
38
    private $injectedInstance;
39
40
    /**
41
     * @var Container 依存コンテナ
42
     */
43
    private $container;
44
45
    /**
46
     * @var Logger ロガー
0 ignored issues
show
Bug introduced by
The type WebStream\Delegate\Logger 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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
47
     */
48
    private $logger;
49
50
    /**
51
     * @var AnnotationContainer アノテーション
0 ignored issues
show
Bug introduced by
The type WebStream\Delegate\AnnotationContainer 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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
52
     */
53
    private $annotation;
54
55
    /**
56
     * @var array<AnnotationContainer> 例外ハンドラリスト
57
     */
58
    private $exceptionHandler;
59
60
    /**
61
     * constructor
62
     */
63
    public function __construct(CoreInterface $instance, Container $container)
64
    {
65
        $this->instance = $instance;
66
        $this->container = $container;
67
        $this->logger = $container->logger;
0 ignored issues
show
Documentation Bug introduced by
It seems like $container->logger can also be of type string. However, the property $logger is declared as type WebStream\Delegate\Logger. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
Bug Best Practice introduced by
The property logger does not exist on WebStream\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
68
    }
69
70
    /**
71
     * method missing
72
     */
73
    public function __call($method, $arguments)
74
    {
75
        return $this->run($method, $arguments);
76
    }
77
78
    /**
79
     * overload getter
80
     */
81
    public function __get($name)
82
    {
83
        return $this->getInstance()->{$name};
84
    }
85
86
    /**
87
     * 処理を実行する
88
     * @param string メソッド名
89
     * @param array 引数リスト
90
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
91
    public function run($method, $arguments = [])
92
    {
93
        // すでに注入済みのインスタンスの場合、そのまま実行
94
        if ($this->injectedInstance !== null) {
95
            return $this->execute($method, $arguments);
96
        }
97
98
        try {
99
            $result = null;
100
            if ($this->instance instanceof CoreController) {
101
                $this->controllerInjector($this->getOriginMethod($method), $arguments);
102
            } elseif ($this->instance instanceof CoreService) {
103
                $result = $this->serviceInjector($this->getOriginMethod($method), $arguments);
104
            } elseif ($this->instance instanceof CoreModel) {
105
                $result = $this->modelInjector($this->getOriginMethod($method), $arguments);
106
            } elseif ($this->instance instanceof CoreView) {
107
                $this->viewInjector($method, $arguments);
108
            } elseif ($this->instance instanceof CoreHelper) {
109
                $result = $this->helperInjector($this->getOriginMethod($method), $arguments);
110
            }
111
112
            return $result;
113
        } catch (DoctrineAnnotationException $e) {
114
            throw new AnnotationException($e);
115
        } catch (DelegateException $e) {
116
            // すでにデリゲート済み例外の場合はそのままスロー
117
            // カスタムアノテーション定義で発生する
118
            throw $e;
119
        } catch (\Exception $e) {
120
            $exceptionClass = get_class($e);
121
            switch ($exceptionClass) {
122
                case "Exception":
123
                case "LogicException":
124
                    $e = new ApplicationException($e->getMessage(), 500, $e);
125
                    break;
126
                case "RuntimeException":
127
                    $e = new SystemException($e->getMessage(), 500, $e);
128
                    break;
129
            }
130
131
            $exception = new ExceptionDelegator($this->getInstance(), $e, $method);
132
            $exception->inject('logger', $this->logger);
133
134
            if ($this->annotation !== null && is_array($this->annotation->exceptionHandler)) {
135
                $exception->setExceptionHandler($this->annotation->exceptionHandler);
136
            }
137
            $exception->raise();
138
        }
139
    }
140
141
    /**
142
     * オリジナルのインスタンスを返却する
143
     * @return CoreInterface インスタンス
144
     */
145
    public function getInstance()
146
    {
147
        return $this->injectedInstance ?: $this->instance;
148
    }
149
150
    /**
151
     * メソッドを実行する
152
     * @param string メソッド名
153
     * @param array 引数リスト
154
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
155
    private function execute($method, $arguments)
156
    {
157
        // serviceの場合、modelの探索に行くためエラーにはしない
158
        if (!($this->injectedInstance instanceof CoreService) && !method_exists($this->injectedInstance, $method)) {
159
            $class = get_class($this->injectedInstance);
160
            throw new MethodNotFoundException("${class}#${method} is not defined.");
161
        }
162
163
        return call_user_func_array([$this->injectedInstance, $method], $arguments);
164
    }
165
166
    /**
167
     * Controllerに注入する
168
     * @param string メソッド名
169
     * @param array 引数リスト
170
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
171
    private function controllerInjector($method, $arguments)
172
    {
173
        if (!method_exists($this->instance, $method)) {
174
            $this->injectedInstance = $this->instance;
175
            $this->instance = null;
176
            $class = get_class($this->instance);
177
            throw new MethodNotFoundException("${class}#${method} is not defined.");
178
        }
179
180
        $applicationInfo = $this->container->applicationInfo;
0 ignored issues
show
Bug Best Practice introduced by
The property applicationInfo does not exist on WebStream\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
181
182
        // テンプレートキャッシュチェック
183
        $pageName = $this->container->coreDelegator->getPageName();
0 ignored issues
show
Bug Best Practice introduced by
The property coreDelegator does not exist on WebStream\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The method getPageName() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

183
        /** @scrutinizer ignore-call */ 
184
        $pageName = $this->container->coreDelegator->getPageName();

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.

Loading history...
184
        $cacheFile = $applicationInfo->cachePrefix . $this->camel2snake($pageName) . "-" . $this->camel2snake($method);
185
186
        $factory = new CacheDriverFactory();
187
        $config = new Container(false);
188
        $config->cacheDir = $applicationInfo->applicationRoot . "/app/views/" . $applicationInfo->cacheDir;
0 ignored issues
show
Bug Best Practice introduced by
The property cacheDir does not exist on WebStream\Container\Container. Since you implemented __set, consider adding a @property annotation.
Loading history...
189
        $config->classPrefix = "view_cache";
0 ignored issues
show
Bug Best Practice introduced by
The property classPrefix does not exist on WebStream\Container\Container. Since you implemented __set, consider adding a @property annotation.
Loading history...
190
        $cache = $factory->create("WebStream\Cache\Driver\TemporaryFile", $config);
191
        $cache->inject('logger', $this->logger);
192
        $data = $cache->get($cacheFile);
193
194
        if ($data !== null) {
195
            $this->logger->debug("Template cache read success: $cacheFile.cache");
196
            echo $data;
197
198
            return;
199
        }
200
201
        $resolver = new Resolver($this->container);
202
        $model = $resolver->runService() ?: $resolver->runModel();
203
204
        // アノテーション注入処理は1度しか行わない
205
        if ($this->injectedInstance === null) {
206
            $this->annotation = $this->container->annotationDelegator->read($this->instance, $method);
207
208
            // @Header
209
            $mimeType = $this->annotation->header->mimeType;
210
211
            // @Filter
212
            $filter = $this->annotation->filter;
213
214
            // @Template
215
            $template = $this->annotation->template;
216
217
            // custom annotation
218
            $this->instance->__customAnnotation($this->annotation->customAnnotations);
219
220
            // 各アノテーションでエラーがあった場合この時点で例外を起こす。
221
            // 例外発生を遅延実行させないとエラーになっていないアノテーション情報が取れない
222
            $exception = $this->annotation->exception;
223
            if ($exception instanceof ExceptionDelegator) {
224
                if ($this->annotation->exceptionHandler !== null) {
225
                    $this->exceptionHandler = $this->annotation->exceptionHandler;
226
                }
227
                $exception->inject('logger', $this->logger);
228
                $exception->setExceptionHandler($this->exceptionHandler);
229
                $exception->raise();
230
            }
231
232
            // initialize filter
233
            $container = $this->container;
234
            $container->model = $model;
235
            foreach ($filter->initialize as $refMethod) {
236
                $refMethod->invokeArgs($this->instance, [$container]);
237
            }
238
239
            // before filter
240
            foreach ($filter->before as $refMethod) {
241
                $refMethod->invoke($this->instance);
242
            }
243
244
            $this->injectedInstance = $this->instance;
245
            $this->execute($method, $arguments);
246
247
            // draw template
248
            $view = $resolver->runView();
249
            $view->setTemplateEngine($template->engine);
250
            $view->draw([
251
                "model" => $model,
252
                "helper" => $resolver->runHelper(),
253
                "mimeType" => $mimeType
254
            ]);
255
256
            if ($template->cacheTime !== null) {
257
                $cacheFile = $applicationInfo->cachePrefix . $this->camel2snake($pageName) . "-" . $this->camel2snake($method);
258
                $view->templateCache($cacheFile, ob_get_contents(), $template->cacheTime);
259
            }
260
261
            // after filter
262
            foreach ($filter->after as $refMethod) {
263
                $refMethod->invoke($this->injectedInstance);
264
            }
265
266
            $this->instance = null;
267
        }
268
    }
269
270
    /**
271
     * Serviceに注入する
272
     * @param string メソッド名
273
     * @param array 引数リスト
274
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
275
    private function serviceInjector($method, $arguments)
276
    {
277
        // アノテーション注入処理は1度しか行わない
278
        if ($this->injectedInstance === null) {
279
            $this->annotation = $this->container->annotationDelegator->read($this->instance, $method);
280
281
            // @Filter
282
            $filter = $this->annotation->filter;
283
284
            // @ExceptionHandler
285
            $this->exceptionHandler = $this->annotation->exceptionHandler;
286
287
            // custom annotation
288
            $this->instance->__customAnnotation($this->annotation->customAnnotations);
289
290
            // 各アノテーションでエラーがあった場合この時点で例外を起こす。
291
            // 例外発生を遅延実行させないとエラーになっていないアノテーション情報が取れない
292
            $exception = $this->annotation->exception;
293
            if ($exception instanceof ExceptionDelegator) {
294
                if ($this->annotation->exceptionHandler !== null) {
295
                    $this->exceptionHandler = $this->annotation->exceptionHandler;
296
                }
297
                $exception->inject('logger', $this->logger);
298
                $exception->setExceptionHandler($this->exceptionHandler);
299
                $exception->raise();
300
            }
301
302
            foreach ($filter->initialize as $refMethod) {
303
                $refMethod->invokeArgs($this->instance, [$this->container]);
304
            }
305
306
            $this->injectedInstance = $this->instance;
307
            $this->instance = null;
308
        }
309
310
        return $this->execute($method, $arguments);
311
    }
312
313
    /**
314
     * Modelに注入する
315
     * @param string メソッド名
316
     * @param array 引数リスト
317
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
318
    private function modelInjector($method, $arguments)
319
    {
320
        // アノテーション注入処理は1度しか行わない
321
        if ($this->injectedInstance === null) {
322
            $this->annotation = $this->container->annotationDelegator->read($this->instance, $method);
323
324
            // @Filter
325
            $filter = $this->annotation->filter;
326
327
            // custom annotation
328
            $this->instance->__customAnnotation($this->annotation->customAnnotations);
329
330
            if ($this->exceptionHandler === null) {
331
                $this->exceptionHandler = $this->annotation->exceptionHandler;
332
            }
333
334
            // 各アノテーションでエラーがあった場合この時点で例外を起こす。
335
            // 例外発生を遅延実行させないとエラーになっていないアノテーション情報が取れない
336
            $exception = $this->annotation->exception;
337
            if ($exception instanceof ExceptionDelegator) {
338
                if ($this->annotation->exceptionHandler !== null) {
339
                    $this->exceptionHandler = $this->annotation->exceptionHandler;
340
                }
341
                $exception->inject('logger', $this->logger);
342
                $exception->setExceptionHandler($this->annotation->exceptionHandler);
343
                $exception->raise();
344
            }
345
346
            $initializeContainer = new Container(false);
347
            $initializeContainer->connectionContainerList = $this->annotation->database;
348
            $initializeContainer->queryAnnotations = $this->annotation->query;
349
350
            foreach ($filter->initialize as $refMethod) {
351
                $refMethod->invokeArgs($this->instance, [$initializeContainer]);
352
            }
353
354
            $this->injectedInstance = $this->instance;
355
            $this->instance = null;
356
        }
357
358
        return $this->execute($method, $arguments);
359
    }
360
361
    /**
362
     * Viewに注入する
363
     * @param string メソッド名
364
     * @param array 引数リスト
365
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
366
    private function viewInjector($method, $arguments)
367
    {
368
        // アノテーション注入処理は1度しか行わない
369
        if ($this->injectedInstance === null) {
370
            $this->annotation = $this->container->annotationDelegator->read($this->instance, $method);
371
372
            // @Filter
373
            $filter = $this->annotation->filter;
374
375
            // 各アノテーションでエラーがあった場合この時点で例外を起こす。
376
            // 例外発生を遅延実行させないとエラーになっていないアノテーション情報が取れない
377
            $exception = $this->annotation->exception;
378
            if ($exception instanceof ExceptionDelegator) {
379
                $exception->inject('logger', $this->logger);
380
                $exception->raise();
381
            }
382
383
            foreach ($filter->initialize as $refMethod) {
384
                $refMethod->invokeArgs($this->instance, [$this->container]);
385
            }
386
387
            $this->injectedInstance = $this->instance;
388
            $this->instance = null;
389
        }
390
391
        $this->execute($method, $arguments);
392
    }
393
394
    /**
395
     * Helperに注入する
396
     * @param string メソッド名
397
     * @param array 引数リスト
398
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment メソッド名 at position 0 could not be parsed: Unknown type name 'メソッド名' at position 0 in メソッド名.
Loading history...
399
    private function helperInjector($method, $arguments)
400
    {
401
        // アノテーション注入処理は1度しか行わない
402
        if ($this->injectedInstance === null) {
403
            $this->annotation = $this->container->annotationDelegator->read($this->instance, $method);
404
405
            // @Filter
406
            $filter = $this->annotation->filter;
407
408
            // custom annotation
409
            $this->instance->__customAnnotation($this->annotation->customAnnotations);
410
411
            if ($this->exceptionHandler === null) {
412
                $this->exceptionHandler = $this->annotation->exceptionHandler;
413
            }
414
415
            // 各アノテーションでエラーがあった場合この時点で例外を起こす。
416
            // 例外発生を遅延実行させないとエラーになっていないアノテーション情報が取れない
417
            $exception = $this->annotation->exception;
418
            if ($exception instanceof ExceptionDelegator) {
419
                if ($this->annotation->exceptionHandler !== null) {
420
                    $this->exceptionHandler = $this->annotation->exceptionHandler;
421
                }
422
                $exception->inject('logger', $this->logger);
423
                $exception->setExceptionHandler($this->annotation->exceptionHandler);
424
                $exception->raise();
425
            }
426
427
            foreach ($filter->initialize as $refMethod) {
428
                $refMethod->invokeArgs($this->instance, [$this->container]);
429
            }
430
431
            $this->injectedInstance = $this->instance;
432
            $this->instance = null;
433
        }
434
435
        return $this->execute($method, $arguments);
436
    }
437
438
    /**
439
     * 実メソッド名を返却する
440
     * @param  stirng $method エイリアスメソッド名
0 ignored issues
show
Bug introduced by
The type WebStream\Delegate\stirng 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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
441
     * @return stirng 実メソッド名
442
     */
443
    private function getOriginMethod($method)
444
    {
445
        // 実メソッドが定義済みの場合、エイリアスメソッド参照はしない
446
        if (method_exists($this->instance, $method)) {
447
            return $method;
448
        }
449
450
        $annotation = $this->container->annotationDelegator->read($this->instance, $method, "WebStream\Annotation\Alias");
0 ignored issues
show
Bug introduced by
The method read() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

450
        /** @scrutinizer ignore-call */ 
451
        $annotation = $this->container->annotationDelegator->read($this->instance, $method, "WebStream\Annotation\Alias");

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.

Loading history...
Bug Best Practice introduced by
The property annotationDelegator does not exist on WebStream\Container\Container. Since you implemented __get, consider adding a @property annotation.
Loading history...
451
452
        $originMethod = null;
453
        foreach ($annotation->alias as $alias) {
454
            if ($originMethod !== null && $alias->{$method} !== null) {
455
                throw new AnnotationException("Alias method of the same name is defined: $method");
456
            }
457
            if ($alias->{$method} !== null) {
458
                $originMethod = $alias->{$method};
459
            }
460
        }
461
462
        if ($originMethod !== null) {
463
            $class = get_class($this->instance);
464
            $this->logger->debug("Alias method found. Transfer from ${class}#${method} to ${class}#${originMethod}.");
465
        } else {
466
            $originMethod = $method;
467
        }
468
469
        return $originMethod;
470
    }
471
}
472