Completed
Push — master ( c1b249...08809f )
by Park Jong-Hun
02:53
created

Application::getErrorReporterInstances()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
3
namespace Core;
4
5
use Prob\Handler\ParameterMap;
6
use Prob\Router\Dispatcher;
7
use Prob\Rewrite\Request;
8
use Prob\Router\Map;
9
use Prob\Router\Matcher;
10
use Doctrine\ORM\Tools\Setup;
11
use Doctrine\ORM\EntityManager;
12
use Core\ErrorReporter;
13
14
class Application
15
{
16
    /**
17
     * @var Map
18
     */
19
    private $routerMap;
20
21
    private $routeConfig = [];
22
    private $siteConfig = [];
23
    private $errorReporterConfig = [];
24
    private $viewEngineConfig = [];
25
    private $dbConfig = [];
26
27
    private $errorReporters = [];
28
29
    /**
30
     * Singleton: private constructor
31
     */
32
    private function __construct()
33
    {
34
    }
35
36
    /**
37
     * @return Application
38
     */
39
    public static function getInstance()
40
    {
41
        static $instance = null;
42
43
        if ($instance === null) {
44
            $instance = new self();
45
        }
46
47
        return $instance;
48
    }
49
50
    public function boot()
51
    {
52
        $this->setSiteConfig(require '../config/site.php');
53
        $this->setErrorReporterConfig(require '../config/errorReporter.php');
54
        $this->setDbConfig(require '../config/db.php');
55
        $this->setViewEngineConfig(require '../config/viewEngine.php');
56
57
        $this->setDisplayError($this->siteConfig['displayErrors']);
58
        $this->registerErrorReporters();
59
60
        $this->setRouterConfig(require '../config/router.php');
61
        $this->dispatcher(new Request());
62
    }
63
64
    public function setSiteConfig(array $siteConfig)
65
    {
66
        $this->siteConfig = $siteConfig;
67
    }
68
69
    public function setErrorReporterConfig(array $errorReporterConfig)
70
    {
71
        $this->errorReporterConfig = $errorReporterConfig;
72
    }
73
74
    public function setDbConfig(array $dbConfig)
75
    {
76
        $this->dbConfig = $dbConfig;
77
    }
78
79
    public function setViewEngineConfig(array $viewEngineConfig)
80
    {
81
        $this->viewEngineConfig = $viewEngineConfig;
82
    }
83
84
    public function setDisplayError($isDisplay)
85
    {
86
        error_reporting(E_ALL);
87
        ini_set('display_errors', $isDisplay);
88
    }
89
90
    public function registerErrorReporters()
91
    {
92
        $this->errorReporters = $this->getErrorReporterInstances();
93
94
        /**
95
         * @var ErrorReporter $reporter
96
         */
97
        set_exception_handler(function ($exception) {
98
            foreach ($this->errorReporters as $reporter) {
99
                $reporter->report($exception);
100
            }
101
        });
102
    }
103
104
    private function getErrorReporterInstances()
105
    {
106
        $enabledReporters = $this->siteConfig['errorReporters'];
107
        $errorReporters = [];
108
109
        foreach ($enabledReporters as $reporter) {
110
            $errorReporters[] = $this->buildErrorReporter($reporter);
111
        }
112
113
        return $errorReporters;
114
    }
115
116
    private function buildErrorReporter($reporterName)
117
    {
118
        $namespace = $this->errorReporterConfig['namespace'];
119
        $class = $namespace. '\\' . $reporterName;
120
121
        $setting = $this->errorReporterConfig[$reporterName];
122
123
        /* @var ErrorReporter */
124
        $reporter = new $class();
125
        $reporter->init($setting);
126
127
        return $reporter;
128
    }
129
130
    public function setRouterConfig(array $routeConfig)
131
    {
132
        $this->routeConfig = $routeConfig;
133
        $this->buildRouterMap();
134
    }
135
136
    private function buildRouterMap()
137
    {
138
        $routerMap = new Map();
139
        $routerMap->setNamespace($this->routeConfig['namespace']);
140
141
        foreach ($this->getRoutePathMap() as $k => $v) {
142
            $this->addRouterMap($routerMap, $k, $v);
143
        }
144
145
        $this->routerMap = $routerMap;
146
    }
147
148
    private function getRoutePathMap()
149
    {
150
        $paths = $this->routeConfig;
151
        unset($paths['namespace']);
152
153
        return $paths;
154
    }
155
156
    /**
157
     * @param Map    $routerMap
158
     * @param string $path  url path
159
     * @param string|array|closure $handler
160
     */
161
    private function addRouterMap(Map $routerMap, $path, $handler)
162
    {
163
        // string | closure
164
        if (gettype($handler) === 'string' || is_callable($handler)) {
165
            $routerMap->get($path, $handler);
166
            return;
167
        }
168
169
        /**
170
         * $handler array schema
171
         * (optional) $handler['GET' | 'POST']
172
         *                => method_name(ex. 'classname.methodname')
173
         *                    or function_name
174
         *                    or closure
175
         */
176
        if (isset($handler['GET'])) {
177
            $routerMap->get($path, $handler['GET']);
178
        }
179
        if (isset($handler['POST'])) {
180
            $routerMap->post($path, $handler['POST']);
181
        }
182
    }
183
184
185
    public function dispatcher(Request $request)
186
    {
187
        $url = $this->resolveUrl($request);
188
        $viewModel = new ViewModel();
189
190
        $parameterMap = new ParameterMap();
191
        $this->bindUrlParameter($parameterMap, $url);
192
        $this->bindViewModelParameter($parameterMap, $viewModel);
193
194
        $returnOfController = $this->executeController($request, $parameterMap);
195
196
        $view = $this->resolveView($returnOfController);
197
        $this->setViewVariables($view, $viewModel->getVariables());
198
        $view->render();
199
    }
200
201
    private function resolveUrl(Request $request)
202
    {
203
        $matcher = new Matcher($this->routerMap);
204
        return $matcher->match($request)['urlNameMatching'] ?: [];
205
    }
206
207
    private function executeController(Request $request, ParameterMap $parameterMap)
208
    {
209
        $dispatcher = new Dispatcher($this->routerMap);
210
        return $dispatcher->dispatch($request, $parameterMap);
211
    }
212
213
    /**
214
     * @param  mixed $returnOfController
215
     * @return View
216
     */
217
    private function resolveView($returnOfController)
218
    {
219
        $viewResolver = new ViewResolver($returnOfController);
220
        return $viewResolver->resolve($this->viewEngineConfig[$this->siteConfig['viewEngine']]);
221
    }
222
223
    private function bindUrlParameter(ParameterMap $map, array $url)
224
    {
225
        $map->bindByNameWithType('array', 'url', $url);
226
227
        foreach ($url as $name => $value) {
228
            $map->bindByName($name, $value);
229
        }
230
    }
231
232
    private function bindViewModelParameter(ParameterMap $map, ViewModel $viewModel)
233
    {
234
        $map->bindByType(ViewModel::class, $viewModel);
235
    }
236
237
    private function setViewVariables(View $view, array $var)
238
    {
239
        foreach ($var as $key => $value) {
240
            $view->set($key, $value);
241
        }
242
    }
243
244
245
    /**
246
     * Return url path with site url
247
     * @param  string $url sub url
248
     * @return string
249
     */
250
    public function url($url = '')
251
    {
252
        return $this->siteConfig['url'] . $url;
253
    }
254
255
256
    /**
257
     * @return EntityManager
258
     */
259
    public function getEntityManager()
260
    {
261
        $config = Setup::createAnnotationMetadataConfiguration(
262
                    $this->dbConfig['entityPath'],
263
                    $this->dbConfig['devMode']
264
                    );
265
        return EntityManager::create($this->dbConfig[$this->siteConfig['database']], $config);
266
    }
267
}
268