Passed
Push — master ( 9b8457...f05bc0 )
by Alexander
01:49
created

Page::getLayoutFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace alkemann\h2l\response;
4
5
use alkemann\h2l\exceptions\InvalidUrl;
6
use alkemann\h2l\exceptions\ConfigMissing;
7
use alkemann\h2l\Log;
8
use alkemann\h2l\Request;
9
use alkemann\h2l\Response;
10
use alkemann\h2l\Environment;
11
12
/**
13
 * Class Page
14
 *
15
 * @package alkemann\h2l
16
 */
17
class Page extends Response
18
{
19
    /**
20
     * Overwrite this in view templates to set layout, i.e. `$this->layout = 'slim';`
21
     *
22
     * @var string
23
     */
24
    public $layout = 'default';
25
26
    /**
27
     * @var Request
28
     */
29
    protected $request;
30
    protected $data = [];
31
    protected $template = 'error';
32
33
    protected $config = [];
34
35
    public function __construct($data = [], array $config = [])
36
    {
37
        $this->data = $data;
38
        foreach (['request', 'type', 'code'] as $key) {
39
            if (isset($config[$key])) {
40
                $this->{$key} = $config[$key];
41
            }
42
        }
43
        if (isset($config['template'])) {
44
            $this->setTemplate($config['template']);
45
        }
46
        $this->config = $config;
47
    }
48
49
    /**
50
     * Analyze the request url to convert to a view template
51
     *
52
     * @param Request $request
53
     * @param array $config
54
     * @return Page
55
     */
56
    public static function fromRequest(Request $request, array $config = []): Page
57
    {
58
        $config += [
59
            'request' => $request,
60
            'type' => $request->type(),
61
        ];
62
        $page = new static([], $config);
63
        $page->template = $config['template'] ?? $page->templateFromUrl($request->route()->url());
64
        return $page;
65
    }
66
67
    /**
68
     * @return bool
69
     * @throws InvalidUrl
70
     */
71
    public function isValid(): bool
72
    {
73
        $file = $this->getContentFile($this->template);
74
        if (!file_exists($file)) {
75
            throw new InvalidUrl("Missing view file: [ $file ]");
76
        }
77
        return true;
78
    }
79
80
    /**
81
     * Provide data (variables) that are to be extracted into the view (and layout) templates
82
     *
83
     * @param string|array $key an array of data or the name for $value
84
     * @param mixed $value if $key is a string, this can be the value of that var
85
     */
86
    public function setData($key, $value = null): void
87
    {
88
        if (is_array($key)) {
89
            foreach ($key as $k => $v) {
90
                $this->data[$k] = $v;
91
            }
92
        } else {
93
            $this->data[$key] = $value;
94
        }
95
    }
96
97
    public function request(): Request
98
    {
99
        return $this->request;
100
    }
101
102
    // @TODO refactor, and cache
103
    private function head(): string
104
    {
105
        ob_start();
106
        try {
107
            $headfile = $this->getLayoutFile('head');
108
            if (file_exists($headfile)) {
109
                (function ($sldkfjlksejflskjflskdjflskdfj) {
110
                    extract($this->data);
111
                    include $sldkfjlksejflskjflskdjflskdfj;
112
                })($headfile);
113
            }
114
115
            $neckfile = $this->getLayoutFile('neck');
116
            if (file_exists($neckfile)) {
117
                (function ($lidsinqjhsdfytqkwjkasjdksadsdg) {
118
                    extract($this->data);
119
                    include $lidsinqjhsdfytqkwjkasjdksadsdg;
120
                })($neckfile);
121
            }
122
        } finally {
123
            $ret = ob_get_contents();
124
            ob_end_clean();
125
        }
126
        return $ret;
127
    }
128
129
    private function getLayoutFile(string $name): string
130
    {
131
        $path = $this->config['layout_path'] ?? Environment::get('layout_path');
132
        if (is_null($path)) {
133
            Log::debug("As there is no configured `layout_path` in Environment, layouts are skipped");
134
        }
135
        return $path . $this->layout . DIRECTORY_SEPARATOR . $name . '.' . $this->type . '.php';
136
    }
137
138
    private function getContentFile(string $view): string
139
    {
140
        $path = $this->config['content_path'] ?? Environment::get('content_path');
141
        if (is_null($path)) {
142
            throw new ConfigMissing("Page requires a `content_path` in Environment");
143
        }
144
        return $path . $view . '.php';
145
    }
146
147
    // @TODO refactor, and cache
148
    private function foot(): string
149
    {
150
        $footfile = $this->getLayoutFile('foot');
151
        if (!file_exists($footfile)) {
152
            return '';
153
        }
154
155
        ob_start();
156
        try {
157
            (function ($ldkfoskdfosjicyvutwehkshfskjdf) {
158
                extract($this->data);
159
                include $ldkfoskdfosjicyvutwehkshfskjdf;
160
            })($footfile);
161
        } finally {
162
            $ret = ob_get_contents();
163
            ob_end_clean();
164
        }
165
        return $ret;
166
    }
167
168
    // @TODO refactor, and cache
169
170
    /**
171
     * @param string $view
172
     * @return string
173
     * @throws InvalidUrl
174
     */
175
    public function view(string $view): string
176
    {
177
        $file = $this->getContentFile($view);
178
        ob_start();
179
        try {
180
            // or another way to hide the file variable?
181
            (function ($dsfjskdfjsdlkfjsdkfjsdkfjsdlkfjsd) {
182
                extract($this->data);
183
                include $dsfjskdfjsdlkfjsdkfjsdkfjsdlkfjsd;
184
            })($file);
185
        } finally {
186
            $ret = ob_get_contents();
187
            ob_end_clean();
188
        }
189
        return $ret;
190
    }
191
192
    /**
193
     * Set header type, render the view, then optionally render layouts and wrap the template
194
     *
195
     * @return string fully rendered string, ready to be echo'ed
196
     * @throws InvalidUrl if the view template does not exist
197
     */
198
    public function render(): string
199
    {
200
        $h = $this->config['header_func'] ?? 'header';
201
        $contentType = $this->contentType();
202
        $h("Content-type: $contentType");
203
        $view = $this->view($this->template);
204
        $response = $this->head();
205
        $response .= $view;
206
        $response .= $this->foot();
207
        return $response;
208
    }
209
210
    /**
211
     * @param string $template
212
     */
213
    public function setTemplate(string $template): void
214
    {
215
        $this->template = "{$template}.{$this->type}";
216
    }
217
218
    /**
219
     * @param null|string $url
220
     * @return string
221
     */
222
    private function templateFromUrl(?string $url = null): string
223
    {
224
        $parts = \explode('/', $url);
225
        $last = \array_slice($parts, -1, 1, true);
226
        unset($parts[key($last)]);
227
        $view = current($last);
228
        $period = strrpos($view, '.');
229
        if ($period) {
230
            $type = substr($view, $period + 1);
231
            if (in_array($type, $this->validTypes)) {
232
                $this->type = $type;
233
                $view = substr($view, 0, $period);
234
            }
235
        }
236
237
        $ret = join(DIRECTORY_SEPARATOR, $parts) . DIRECTORY_SEPARATOR . $view . '.' . $this->type;
238
        return trim($ret, DIRECTORY_SEPARATOR);
239
    }
240
}
241