Passed
Push — main ( 6e2268...e66a08 )
by Sammy
01:33
created

hopper::match()   A

Complexity

Conditions 5
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 5
eloc 10
c 3
b 0
f 0
nc 3
nop 2
dl 0
loc 18
rs 9.6111
1
<?php
2
3
/**
4
* huppel konijntje huppel and wiebel
5
* Hommage to Grace Hopper, programmer & expert in *litteral* duck taping
6
***/
7
8
namespace HexMakina\Hopper;
9
10
class hopper extends \AltoRouter implements RouterInterface
11
{
12
    private $match = null;
13
    private $file_root = null;
14
    private $controller_namespaces = null;
15
16
  //----------------------------------------------------------- INITIALISATION
17
    public function __construct($settings)
18
    {
19
        if (!isset($settings['route_home'])) {
20
            throw new RouterException('ROUTE_HOME_UNDEFINED');
21
        }
22
23
        parent::__construct();
24
25
        $this->set_web_base($settings['web_base'] ?? '');
26
        $this->set_file_root($settings['file_root'] ?? __DIR__);
27
28
        $this->controller_namespaces = $settings['controllers_namespaces'] ?? [];
29
30
        $this->map(self::REQUEST_GET, '', $settings['route_home'], self::ROUTE_HOME_NAME);
31
    }
32
33
    public function __debugInfo(): array
34
    {
35
        $dbg = get_object_vars($this);
36
        $dbg['routes'] = count($dbg['routes']);
37
        $dbg['namedRoutes'] = count($dbg['namedRoutes']);
38
        unset($dbg['matchTypes']);
39
        return $dbg;
40
    }
41
  // -- MATCHING REQUESTS
42
    public function match($requestUrl = null, $requestMethod = null)
43
    {
44
        $this->match = parent::match($requestUrl, $requestMethod);
45
46
        if ($this->match === false) {
47
            throw new RouterException('ROUTE_MATCH_FALSE');
48
        }
49
50
        $res = explode('::', $this->target());
51
52
        if ($res === false || !isset($res[1]) || isset($res[2])) {
53
            throw new RouterException('INVALID_TARGET_FORMAT');
54
        }
55
56
        $this->match['target_controller'] = $res[0];
57
        $this->match['target_method'] = $res[1];
58
59
        return [$res[0], $res[1]];
60
61
        // $target_controller = $res[0];
62
        // $target_method = $res[1];
63
        // $found = false;
64
        //
65
        // $controller_class_name = null;
66
        // foreach ($this->controller_namespaces as $controller_ns) {
67
        //     if ($found = class_exists($controller_class_name = "$controller_ns$target_controller")) {
68
        //         break;
69
        //     }
70
        // }
71
        //
72
        // if ($found === false) {
73
        //     throw new RouterException('INVALID_CONTROLLER_NAME');
74
        // }
75
76
        // $this->match['target_controller'] = $controller_class_name;
77
        // $this->match['target_method'] = $target_method;
78
        //
79
        // return [$controller_class_name, $target_method];
80
    }
81
82
    public function params($param_name = null)
83
    {
84
        return $this->extract_request($this->match['params'] ?? [], $param_name);
85
    }
86
87
    public function submitted($param_name = null)
88
    {
89
        return $this->extract_request($_POST, $param_name);
90
    }
91
92
    private function extract_request($dat_ass, $key = null)
93
    {
94
95
      // $key is null, returns $dat_ass or empty array
96
        if (is_null($key)) {
97
            return $dat_ass ?? [];
98
        }
99
100
      // $dat_ass[$key] not set, returns null
101
        if (!isset($dat_ass[$key])) {
102
            return null;
103
        }
104
105
      // $dat_ass[$key] is a string, returns decoded value
106
        if (is_string($dat_ass[$key])) {
107
            return urldecode($dat_ass[$key]);
108
        }
109
110
      // $dat_ass[$key] is not a string, return match[$key]
111
        return $dat_ass[$key];
112
    }
113
114
    public function target()
115
    {
116
        return $this->match['target'];
117
    }
118
119
    public function target_controller()
120
    {
121
        return $this->match['target_controller'];
122
    }
123
124
    public function target_method()
125
    {
126
        return $this->match['target_method'];
127
    }
128
129
    public function name()
130
    {
131
        return $this->match['name'];
132
    }
133
134
  // -- ROUTING TOOLS
135
    public function route_exists($route): bool
136
    {
137
        return isset($this->namedRoutes[$route]);
138
    }
139
140
    public function named_routes()
141
    {
142
        return $this->namedRoutes;
143
    }
144
145
  /*
146
   * @param route_name string  requires
147
   *  - a valid AltoRouter route name
148
   *  - OR a Descendant of Model
149
   * @route_params requires
150
   *  - an assoc_array of url params (strongly AltoRouter-based)
151
   * returns: something to put in a href="", action="" or header('Location:');
152
   */
153
    public function prehop($route, $route_params = [])
154
    {
155
        try {
156
            $url = $this->generate($route, $route_params);
157
        } catch (\Exception $e) {
158
            $url = $this->prehop(self::ROUTE_HOME_NAME);
159
        }
160
161
        return $url;
162
    }
163
164
    public function prehop_here($url = null)
165
    {
166
        return $url ?? $_SERVER['REQUEST_URI'];
167
    }
168
169
  /*
170
   * @params $route is
171
   *    - empty: default is ROUTE_HOME_NAME
172
   *    - an existing route name: make url with optional [$route_params])
173
   *    - a url, go there
174
   * @params $route_params, assoc_data for url creation (i:id, a:format, ..)
175
   */
176
    public function hop($route = null, $route_params = [])
177
    {
178
        $url = null;
179
180
        if (is_null($route)) {
181
            $url = $this->prehop(self::ROUTE_HOME_NAME, $route_params);
182
        } elseif (is_string($route) && $this->route_exists($route)) {
183
            $url = $this->prehop($route, $route_params);
184
        } else {
185
            $url = $route;
186
        }
187
188
        $this->hop_url($url);
189
    }
190
191
  // hops back to previous page (referer()), or home if no referer
192
    public function hop_back()
193
    {
194
        if (!is_null($back = $this->referer())) {
195
            $this->hop_url($back);
196
        }
197
198
        $this->hop();
199
    }
200
201
    public function hop_url($url)
202
    {
203
        header('Cache-Control: no-cache, must-revalidate');
204
        header('Expires: Mon, 01 Jan 1970 00:00:00 GMT');
205
        header('Location: ' . $url);
206
        exit();
207
    }
208
209
  // returns full URL of the refering URL
210
  // returns null if same as current URL (prevents endless redirection loop)
211
    public function referer()
212
    {
213
        if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != $this->web_host() . $_SERVER['REQUEST_URI']) {
214
            return $_SERVER['HTTP_REFERER'];
215
        }
216
217
        return null;
218
    }
219
220
    public function send_file($file_path)
221
    {
222
        if (!file_exists($file_path)) {
223
            throw new RouterException('SENDING_NON_EXISTING_FILE');
224
        }
225
226
        $file_name = basename($file_path);
227
228
      //Get file type and set it as Content Type
229
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
230
231
        header('Content-Type: ' . finfo_file($finfo, $file_path));
232
233
        finfo_close($finfo);
234
235
      //Use Content-Disposition: attachment to specify the filename
236
        header('Content-Disposition: attachment; filename=' . $file_name);
237
238
      //No cache
239
        header('Expires: 0');
240
        header('Cache-Control: must-revalidate');
241
        header('Pragma: public');
242
243
      //Define file size
244
        header('Content-Length: ' . filesize($file_path));
245
246
        ob_clean();
247
        flush();
248
        readfile($file_path);
249
        // die; // might be useless after all
250
    }
251
252
  // -- PROCESSING REQUESTS
253
    public function requests(): bool
254
    {
255
        return $_SERVER['REQUEST_METHOD'] === self::REQUEST_GET;
256
    }
257
258
    public function submits(): bool
259
    {
260
        return $_SERVER['REQUEST_METHOD'] === self::REQUEST_POST;
261
    }
262
263
    public function web_host(): string
264
    {
265
        return $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
266
    }
267
268
    public function web_root(): string
269
    {
270
        return $this->web_host() . $this->web_base();
271
    }
272
273
    public function web_base(): string
274
    {
275
        return $this->basePath ?? '';
276
    }
277
278
    public function set_web_base($setter)
279
    {
280
        $this->setBasePath($setter);
281
    }
282
283
    public function file_root(): string
284
    {
285
        return $this->file_root ?? __DIR__;
286
    }
287
288
    public function set_file_root($setter)
289
    {
290
        $this->file_root = realpath($setter) . '/';
291
    }
292
}
293