Completed
Push — 6.0 ( 0c4689...2069b0 )
by yun
27s queued 19s
created

Controller::parseActions()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think\route\dispatch;
14
15
use ReflectionClass;
16
use ReflectionException;
17
use ReflectionMethod;
18
use think\App;
19
use think\exception\ClassNotFoundException;
20
use think\exception\HttpException;
21
use think\helper\Str;
22
use think\route\Dispatch;
23
24
/**
25
 * Controller Dispatcher
26
 */
27
class Controller extends Dispatch
28
{
29
    /**
30
     * 控制器名
31
     * @var string
32
     */
33
    protected $controller;
34
35
    /**
36
     * 操作名
37
     * @var string
38
     */
39
    protected $actionName;
40
41 15
    public function init(App $app)
42
    {
43 15
        parent::init($app);
44
45 15
        $result = $this->dispatch;
46
47 15
        if (is_string($result)) {
48
            $result = explode('/', $result);
49
        }
50
51
        // 获取控制器名
52 15
        $controller = strip_tags($result[0] ?: $this->rule->config('default_controller'));
0 ignored issues
show
Bug introduced by
It seems like $result[0] ?: $this->rul...g('default_controller') can also be of type null; however, parameter $string of strip_tags() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

52
        $controller = strip_tags(/** @scrutinizer ignore-type */ $result[0] ?: $this->rule->config('default_controller'));
Loading history...
53
54 15
        if (strpos($controller, '.')) {
55
            $pos              = strrpos($controller, '.');
56
            $this->controller = substr($controller, 0, $pos) . '.' . Str::studly(substr($controller, $pos + 1));
57
        } else {
58 15
            $this->controller = Str::studly($controller);
59
        }
60
61
        // 获取操作名
62 15
        $this->actionName = strip_tags($result[1] ?: $this->rule->config('default_action'));
63
64
        // 设置当前请求的控制器、操作
65 15
        $this->request
66 15
            ->setController($this->controller)
67 15
            ->setAction($this->actionName);
68 15
    }
69
70 12
    public function exec()
71
    {
72
        try {
73
            // 实例化控制器
74 12
            $instance = $this->controller($this->controller);
75
        } catch (ClassNotFoundException $e) {
76
            throw new HttpException(404, 'controller not exists:' . $e->getClass());
77
        }
78
79
        // 注册控制器中间件
80 12
        $this->registerControllerMiddleware($instance);
81
82 12
        return $this->app->middleware->pipeline('controller')
83 12
            ->send($this->request)
84
            ->then(function () use ($instance) {
85
                // 获取当前操作名
86 12
                $suffix = $this->rule->config('action_suffix');
87 12
                $action = $this->actionName . $suffix;
88
89 12
                if (is_callable([$instance, $action])) {
90 12
                    $vars = $this->request->param();
91
                    try {
92 12
                        $reflect = new ReflectionMethod($instance, $action);
93
                        // 严格获取当前操作方法名
94 3
                        $actionName = $reflect->getName();
95 3
                        if ($suffix) {
96
                            $actionName = substr($actionName, 0, -strlen($suffix));
97
                        }
98
99 3
                        $this->request->setAction($actionName);
100 9
                    } catch (ReflectionException $e) {
101 9
                        $reflect = new ReflectionMethod($instance, '__call');
102 9
                        $vars    = [$action, $vars];
103 12
                        $this->request->setAction($action);
104
                    }
105
                } else {
106
                    // 操作不存在
107
                    throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
108
                }
109
110 12
                $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);
111
112 12
                return $this->autoResponse($data);
113 12
            });
114
    }
115
116
    protected function parseActions($actions)
117
    {
118
        return array_map(function ($item) {
119
            return strtolower($item);
120
        }, is_string($actions) ? explode(",", $actions) : $actions);
121
    }
122 12
123
    /**
124 12
     * 使用反射机制注册控制器中间件
125
     * @access public
126 12
     * @param object $controller 控制器实例
127 6
     * @return void
128 6
     */
129
    protected function registerControllerMiddleware($controller): void
130 6
    {
131
        $class = new ReflectionClass($controller);
132 6
133 3
        if ($class->hasProperty('middleware')) {
134
            $reflectionProperty = $class->getProperty('middleware');
135 3
            $reflectionProperty->setAccessible(true);
136 3
137
            $middlewares = $reflectionProperty->getValue($controller);
138
            $action      = $this->request->action(true);
139 3
140 3
            foreach ($middlewares as $key => $val) {
141 3
                if (!is_int($key)) {
142
                    $middleware = $key;
143 3
                    $options    = $val;
144
                } elseif (isset($val['middleware'])) {
145
                    $middleware = $val['middleware'];
146
                    $options    = $val['options'] ?? [];
147 3
                } else {
148 3
                    $middleware = $val;
149 3
                    $options    = [];
150 3
                }
151
152
                if (isset($options['only']) && !in_array($action, $this->parseActions($options['only']))) {
153
                    continue;
154 3
                } elseif (isset($options['except']) && in_array($action, $this->parseActions($options['except']))) {
155
                    continue;
156
                }
157 12
158
                if (is_string($middleware) && strpos($middleware, ':')) {
159
                    $middleware = explode(':', $middleware);
160
                    if (count($middleware) > 1) {
161
                        $middleware = [$middleware[0], array_slice($middleware, 1)];
162
                    }
163
                }
164
165
                $this->app->middleware->controller($middleware);
166 12
            }
167
        }
168 12
    }
169
170 12
    /**
171 12
     * 实例化访问控制器
172
     * @access public
173 12
     * @param string $name 资源地址
174
     * @return object
175 12
     * @throws ClassNotFoundException
176 9
     */
177 3
    public function controller(string $name)
178 3
    {
179
        $suffix = $this->rule->config('controller_suffix') ? 'Controller' : '';
180
181
        $controllerLayer = $this->rule->config('controller_layer') ?: 'controller';
182
        $emptyController = $this->rule->config('empty_controller') ?: 'Error';
183
184
        $class = $this->app->parseClass($controllerLayer, $name . $suffix);
185
186
        if (class_exists($class)) {
187
            return $this->app->make($class, [], true);
188
        } elseif ($emptyController && class_exists($emptyClass = $this->app->parseClass($controllerLayer, $emptyController . $suffix))) {
189
            return $this->app->make($emptyClass, [], true);
190
        }
191
192
        throw new ClassNotFoundException('class not exists:' . $class, $class);
193
    }
194
}
195