Completed
Push — master ( 5ffcea...f37f42 )
by Park Jong-Hun
03:00
created

Dispatcher::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Core\ControllerDispatcher;
4
5
use Prob\Handler\ProcInterface;
6
use Prob\Handler\ParameterMap;
7
use Psr\Http\Message\ServerRequestInterface;
8
use Prob\Router\Dispatcher as RouterDispatcher;
9
use Prob\Router\Matcher;
10
use Prob\Router\Map;
11
use Core\ViewModel;
12
use Core\Event\EventManager;
13
use Core\ViewEngineInterface;
14
use Core\ViewResolverInterface;
15
16
class Dispatcher
17
{
18
    /**
19
     * @var Map
20
     */
21
    private $routerMap;
22
    private $routerConfig = [];
23
    private $viewEngineConfig = [];
24
25
    private $viewResolvers = [];
26
27
    /**
28
     * @var ViewModel
29
     */
30
    private $viewModel;
31
32
    /**
33
     * @var ServerRequestInterface
34
     */
35
    private $request;
36
37
    public function __construct()
38
    {
39
        $this->viewModel = new ViewModel();
40
    }
41
42
    public function setRouterConfig(array $routerConfig)
43
    {
44
        $this->routerConfig = $routerConfig;
45
    }
46
47
    public function setViewEngineConfig(array $config)
48
    {
49
        $this->viewEngineConfig = $config;
50
    }
51
52
    public function setViewResolver(array $viewResolvers)
53
    {
54
        $this->viewResolvers = $viewResolvers;
55
    }
56
57
    public function setRequest(ServerRequestInterface $request)
58
    {
59
        $this->request = $request;
60
    }
61
62
    public function dispatch()
63
    {
64
        $this->buildRouterMap();
65
66
        $parameterMap = $this->getParameterMap();
67
68
        $result = $this->execute($parameterMap);
69
        $this->renderView($result);
70
    }
71
72
    private function buildRouterMap()
73
    {
74
        $builder = new RouterMapBuilder();
75
        $builder->setRouterConfig($this->routerConfig);
76
77
        $this->routerMap = $builder->build();
78
    }
79
80
    /**
81
     * @return ParameterMap
82
     */
83
    private function getParameterMap()
84
    {
85
        $parameterMapper = new ParameterMapper();
86
87
        $parameterMapper->setRequest($this->request);
88
        $parameterMapper->setViewModel($this->viewModel);
89
        $parameterMapper->setRouterMap($this->routerMap);
90
91
        return $parameterMapper->getParameterMap();
92
    }
93
94
95
    private function execute(ParameterMap $parameterMap)
96
    {
97
        $dispatcher = new RouterDispatcher($this->routerMap);
98
99
        /**
100
         * TODO 클로저와 일반함수 형태에서도 컨트롤러 이벤트가 작동하도록 수정해야함.
101
         */
102
103
        if ($this->getMatchedHandler()) {
104
            $this->triggerEvent($this->getEventName('before'));
105
        }
106
107
        $result = $dispatcher->dispatch($this->request, $parameterMap);
108
109
        if ($this->getMatchedHandler()) {
110
            $this->triggerEvent($this->getEventName('after'));
111
        }
112
113
        return $result;
114
    }
115
116
    /**
117
     * @param  string $action 'before' || 'after'
118
     * @return string event name
119
     */
120
    private function getEventName($action)
121
    {
122
        return sprintf(
123
            'Controller.%s.%s',
124
            $this->getMatchedHandler()->getName(),
125
            $action
126
        );
127
    }
128
129
    /**
130
     * @return ProcInterface
131
     */
132
    private function getMatchedHandler()
133
    {
134
        $matcher = new Matcher($this->routerMap);
135
        return $matcher->match($this->request)['handler'];
136
    }
137
138
    private function triggerEvent($eventName)
139
    {
140
        EventManager::getEventManager()->trigger($eventName, [$this->getParameterMap()]);
141
    }
142
143
    private function renderView($controllerResult)
144
    {
145
        $view = $this->resolveView($controllerResult);
146
147
        foreach ($this->viewModel->getVariables() as $key => $value) {
148
            $view->set($key, $value);
149
        }
150
151
        $view->render();
152
    }
153
154
    /**
155
     * @param  mixed $controllerResult
156
     * @return ViewEngineInterface
157
     */
158
    private function resolveView($controllerResult)
159
    {
160
        foreach ($this->viewResolvers as $name => $resolverClassName) {
161
            /** @var ViewResolverInterface */
162
            $resolver = new $resolverClassName();
163
            $resolver->setViewEngineConfig(
164
                isset($this->viewEngineConfig[$name])
165
                    ? $this->viewEngineConfig[$name]
166
                    : []
167
            );
168
169
            $view = $resolver->resolve($controllerResult);
170
171
            if ($view !== null) {
172
                return $view;
173
            }
174
        }
175
    }
176
}
177