Completed
Push — master ( 7e0bd3...afb851 )
by Anton
16s
created

Controller::getTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link      https://github.com/bluzphp/framework
7
 */
8
9
declare(strict_types=1);
10
11
namespace Bluz\Controller;
12
13
use Bluz\Application\Application;
14
use Bluz\Auth\EntityInterface;
15
use Bluz\Common\Exception\CommonException;
16
use Bluz\Common\Exception\ComponentException;
17
use Bluz\Common\Helper;
18
use Bluz\Proxy\Cache;
19
use Bluz\Proxy\Logger;
20
use Bluz\Response\ResponseTrait;
21
use Bluz\View\View;
22
23
/**
24
 * Statement
25
 *
26
 * @package  Bluz\Controller
27
 * @author   Anton Shevchuk
28
 *
29
 * @method void attachment(string $file)
30
 * @method void checkHttpAccept()
31
 * @method void checkHttpMethod()
32
 * @method void checkPrivilege()
33
 * @method void denied()
34
 * @method void disableLayout()
35
 * @method void disableView()
36
 * @method Controller dispatch(string $module, string $controller, array $params = [])
37
 * @method void redirect(string $url)
38
 * @method void redirectTo(string $module, string $controller, array $params = [])
39
 * @method void reload()
40
 * @method bool isAllowed($privilege)
41
 * @method void useJson()
42
 * @method void useLayout($layout)
43
 * @method EntityInterface user()
44
 */
45
class Controller implements \JsonSerializable
46
{
47
    use Helper;
48
    use ResponseTrait;
49
50
    /**
51
     * @var string
52
     */
53
    protected $module;
54
55
    /**
56
     * @var string
57
     */
58
    protected $controller;
59
60
    /**
61
     * @var array
62
     */
63
    protected $params;
64
65
    /**
66
     * @var string Cache key
67
     */
68
    protected $key;
69
70
    /**
71
     * @var string Template name, by default is equal to controller name
72
     */
73
    protected $template;
74
75
    /**
76
     * @var string
77
     */
78
    protected $file;
79
80
    /**
81
     * @var Meta
82
     */
83
    protected $meta;
84
85
    /**
86
     * @var Data
87
     */
88
    protected $data;
89
90
    /**
91
     * Constructor of Statement
92
     *
93
     * @param string $module
94
     * @param string $controller
95
     * @param array  $params
96
     *
97
     * @throws CommonException
98
     */
99 725
    public function __construct($module, $controller, array $params = [])
100
    {
101
        // initial default helper path
102 725
        $this->addHelperPath(__DIR__ . '/Helper/');
103
104 725
        $this->setModule($module);
105 725
        $this->setController($controller);
106 725
        $this->setParams($params);
107 725
        $this->setTemplate($controller . '.phtml');
108
109 725
        $this->key = "data.$module.$controller." . md5(http_build_query($params));
110 725
    }
111
112
    /**
113
     * @return string
114
     */
115
    public function getModule(): string
116
    {
117
        return $this->module;
118
    }
119
120
    /**
121
     * @param string $module
122
     */
123 725
    protected function setModule(string $module)
124
    {
125 725
        $this->module = $module;
126 725
    }
127
128
    /**
129
     * @return string
130
     */
131
    public function getController(): string
132
    {
133
        return $this->controller;
134
    }
135
136
    /**
137
     * @param string $controller
138
     */
139 725
    protected function setController(string $controller)
140
    {
141 725
        $this->controller = $controller;
142 725
    }
143
144
    /**
145
     * @return array
146
     */
147
    public function getParams(): array
148
    {
149
        return $this->params;
150
    }
151
152
    /**
153
     * @param array $params
154
     */
155 725
    protected function setParams(array $params)
156
    {
157 725
        $this->params = $params;
158 725
    }
159
160
    /**
161
     * @return string
162
     */
163 2
    public function getTemplate()
164
    {
165 2
        return $this->template;
166
    }
167
168
    /**
169
     * @param string $template
170
     */
171 725
    protected function setTemplate(string $template)
172
    {
173 725
        $this->template = $template;
174 725
    }
175
176
    /**
177
     * Run controller logic
178
     *
179
     * @return Data
180
     * @throws ComponentException
181
     * @throws ControllerException
182
     */
183 20
    public function run(): Data
184
    {
185 20
        if (!$this->loadData()) {
186 20
            $this->process();
187 18
            $this->saveData();
188
        }
189 18
        return $this->data;
190
    }
191
192
    /**
193
     * Controller run
194
     *
195
     * @return Data
196
     * @throws ComponentException
197
     * @throws ControllerException
198
     */
199 20
    protected function process(): Data
200
    {
201
        // initial variables for use inside controller
202 20
        $module = $this->module;
203 20
        $controller = $this->controller;
204 20
        $params = $this->params;
205
206
        /**
207
         * @var \closure $controllerClosure
208
         */
209 20
        $controllerClosure = include $this->getFile();
210
211 20
        if (!is_callable($controllerClosure)) {
212
            throw new ControllerException("Controller is not callable '{$module}/{$controller}'");
213
        }
214
215
        // process params
216 20
        $params = $this->getMeta()->params($params);
217
218
        // call Closure or Controller
219 20
        $result = $controllerClosure(...$params);
220
221
        // switch statement for result of Closure run
222
        switch (true) {
223 18
            case ($result === false):
224
                // return "false" is equal to disable view and layout
225 6
                $this->disableLayout();
226 6
                $this->disableView();
227 6
                break;
228 13
            case is_string($result):
229
                // return string variable is equal to change view template
230
                $this->setTemplate($result);
231
                break;
232 13
            case is_array($result):
233
                // return associative array is equal to setup view data
234 3
                $this->getData()->setFromArray($result);
235 3
                break;
236 10
            case ($result instanceof Controller):
237
                $this->getData()->setFromArray($result->getData()->toArray());
238
                break;
239
        }
240
241 18
        return $this->getData();
242
    }
243
244
    /**
245
     * Setup controller file
246
     *
247
     * @return void
248
     * @throws ControllerException
249
     */
250 725
    protected function findFile()
251
    {
252 725
        $path = Application::getInstance()->getPath();
253 725
        $file = "$path/modules/{$this->module}/controllers/{$this->controller}.php";
254
255 725
        if (!file_exists($file)) {
256 3
            throw new ControllerException("Controller file not found '{$this->module}/{$this->controller}'", 404);
257
        }
258
259 725
        $this->file = $file;
260 725
    }
261
262
    /**
263
     * Get controller file path
264
     *
265
     * @return string
266
     * @throws ControllerException
267
     */
268 725
    protected function getFile(): string
269
    {
270 725
        if (!$this->file) {
271 725
            $this->findFile();
272
        }
273 725
        return $this->file;
274
    }
275
276
    /**
277
     * Retrieve reflection for anonymous function
278
     *
279
     * @return void
280
     * @throws ComponentException
281
     * @throws ControllerException
282
     */
283 725
    protected function initMeta()
284
    {
285
        // cache for reflection data
286 725
        $cacheKey = "meta.{$this->module}.{$this->controller}";
287
288 725
        if (!$meta = Cache::get($cacheKey)) {
289 725
            $meta = new Meta($this->getFile());
290 725
            $meta->process();
291
292 725
            Cache::set(
293 725
                $cacheKey,
294 725
                $meta,
295 725
                Cache::TTL_NO_EXPIRY,
296 725
                ['system', 'meta']
297
            );
298
        }
299 725
        $this->meta = $meta;
300 725
    }
301
302
    /**
303
     * Get meta information
304
     *
305
     * @return Meta
306
     * @throws ControllerException
307
     * @throws ComponentException
308
     */
309 725
    public function getMeta(): Meta
310
    {
311 725
        if (!$this->meta) {
312 725
            $this->initMeta();
313
        }
314 725
        return $this->meta;
315
    }
316
317
    /**
318
     * Assign key/value pair to Data object
319
     *
320
     * @param  string $key
321
     * @param  mixed  $value
322
     *
323
     * @return void
324
     */
325 1
    public function assign($key, $value)
326
    {
327 1
        $this->getData()->set($key, $value);
328 1
    }
329
330
    /**
331
     * Get controller Data container
332
     *
333
     * @return Data
334
     */
335 18
    public function getData(): Data
336
    {
337 18
        if (!$this->data) {
338 18
            $this->data = new Data();
339
        }
340 18
        return $this->data;
341
    }
342
343
    /**
344
     * Load Data from cache
345
     *
346
     * @return bool
347
     * @throws ComponentException
348
     * @throws ControllerException
349
     */
350 20
    private function loadData(): bool
351
    {
352 20
        $cacheTime = $this->getMeta()->getCache();
353
354 20
        if ($cacheTime && $cached = Cache::get($this->key)) {
355
            $this->data = $cached;
356
            return true;
357
        }
358 20
        return false;
359
    }
360
361
    /**
362
     * Save Data to cache
363
     *
364
     * @return bool
365
     * @throws ComponentException
366
     * @throws ControllerException
367
     */
368 18
    private function saveData(): bool
369
    {
370 18
        if ($cacheTime = $this->getMeta()->getCache()) {
371
            return Cache::set(
372
                $this->key,
373
                $this->getData(),
374
                $cacheTime,
375
                ['system', 'data']
376
            );
377
        }
378 18
        return false;
379
    }
380
381
    /**
382
     * Specify data which should be serialized to JSON
383
     *
384
     * @return Data
385
     */
386
    public function jsonSerialize()
387
    {
388
        return $this->getData();
389
    }
390
391
    /**
392
     * Magic cast to string
393
     *
394
     * @return string
395
     */
396 2
    public function __toString()
397
    {
398 2
        if (!$this->template) {
399
            return '';
400
        }
401
402
        try {
403
            // $view for use in closure
404 2
            $view = new View();
405
406 2
            $path = Application::getInstance()->getPath();
407
408
            // setup additional helper path
409 2
            $view->addHelperPath($path . '/layouts/helpers');
410
411
            // setup additional partial path
412 2
            $view->addPartialPath($path . '/layouts/partial');
413
414
            // setup default path
415 2
            $view->setPath($path . '/modules/' . $this->module . '/views');
416
417
            // setup template
418 2
            $view->setTemplate($this->template);
419
420
            // setup data
421 2
            $view->setFromArray($this->getData()->toArray());
422 2
            return $view->render();
423
        } catch (\Exception $e) {
424
            // save log
425
            Logger::error($e->getMessage());
426
            return '';
427
        }
428
    }
429
}
430