Passed
Push — main ( 14e4e9...d1069b )
by Sammy
01:20
created

hopper.php (5 issues)

1
<?php
2
/**
3
* huppel konijntje huppel and wiebel
4
* Hommage to Grace Hopper, programmer & expert in *litteral* duck taping
5
***/
6
7
namespace HexMakina\Hopper;
8
9
class hopper extends \AltoRouter implements RouterInterface
10
{
11
  private $match=null;
12
  private $file_root=null;
13
  private $controller_namespaces = null;
14
15
  //----------------------------------------------------------- INITIALISATION
16
  public function __construct($settings)
17
  {
18
    if(!isset($settings['route_home']))
19
      throw new RouterException('ROUTE_HOME_UNDEFINED');
20
21
    parent::__construct();
22
23
    $this->set_web_base($settings['web_base'] ?? '');
24
    $this->set_file_root($settings['file_root'] ?? __DIR__);
25
26
    $this->controller_namespaces = $settings['controllers_namespaces'] ?? [];
27
28
    list($url, $controller_method, $name) = $settings['route_home'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
This list assign is not used and could be removed.
Loading history...
29
    $this->map(self::REQUEST_GET, '', $settings['route_home'], self::ROUTE_HOME_NAME);
30
  }
31
32
  public function __debugInfo() : array
33
  {
34
    $dbg = get_object_vars($this);
35
    $dbg['routes'] = count($dbg['routes']);
36
    $dbg['namedRoutes'] = count($dbg['namedRoutes']);
37
    unset($dbg['matchTypes']);
38
    return $dbg;
39
  }
40
  // ----------------------------------------------------------- MATCHING REQUESTS
41
  public function match($requestUrl = NULL, $requestMethod = NULL)
42
  {
43
    $this->match = parent::match($requestUrl, $requestMethod);
44
45
    if($this->match === false)
1 ignored issue
show
The condition $this->match === false is always false.
Loading history...
46
      throw new RouterException('ROUTE_MATCH_FALSE');
47
48
    $res = explode('::', self::target());
0 ignored issues
show
Bug Best Practice introduced by
The method HexMakina\Hopper\hopper::target() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

48
    $res = explode('::', self::/** @scrutinizer ignore-call */ target());
Loading history...
49
50
    if($res === false || !isset($res[1]) || isset($ret[2]))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ret seems to never exist and therefore isset should always be false.
Loading history...
51
      throw new RouterException('INVALID_TARGET');
52
53
    // if($this->match['name'] === 'akadok_controller_method')
54
    //   $res = [ucfirst(self::params('controller')).'Controller', ucfirst(self::params('method'))];
55
56
57
    $target_controller = $res[0];
58
    $target_method = $res[1];
59
    $found = false;
60
61
    foreach($this->controller_namespaces as $controller_ns)
62
      if($found = class_exists($controller_class_name = "$controller_ns$target_controller"))
63
        break;
64
65
    if($found === false)
66
      throw new RouterException('INVALID_CONTROLLER_NAME');
67
68
    $this->match['target_controller'] = $controller_class_name;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $controller_class_name seems to be defined by a foreach iteration on line 61. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
69
    $this->match['target_method'] = $target_method;
70
71
    return [$controller_class_name, $target_method];
72
  }
73
74
  public function params($param_name=null)
75
  {
76
    return $this->extract_request($this->match['params'] ?? [], $param_name);
77
  }
78
79
  public function submitted($param_name=null)
80
  {
81
    return $this->extract_request($_POST, $param_name);
82
  }
83
84
  private function extract_request($dat_ass, $key=null)
85
  {
86
87
    // $key is null, returns $dat_ass or empty array
88
    if(is_null($key))
89
      return $dat_ass ?? [];
90
91
    // $dat_ass[$key] not set, returns null
92
    if(!isset($dat_ass[$key]))
93
      return null;
94
95
    // $dat_ass[$key] is a string, returns decoded value
96
    if(is_string($dat_ass[$key]))
97
      return urldecode($dat_ass[$key]);
98
99
    // $dat_ass[$key] is not a string, return match[$key]
100
    return $dat_ass[$key];
101
102
  }
103
104
  public function target()
105
  {
106
    return $this->match['target'];
107
  }
108
109
  public function target_controller()
110
  {
111
    return $this->match['target_controller'];
112
  }
113
114
  public function target_method()
115
  {
116
    return $this->match['target_method'];
117
  }
118
119
  public function name()
120
  {
121
    return $this->match['name'];
122
  }
123
124
  // ----------------------------------------------------------- ROUTING TOOLS
125
  public function route_exists($route) : bool
126
  {
127
    return isset($this->namedRoutes[$route]);
128
  }
129
130
  public function named_routes()
131
  {
132
    return $this->namedRoutes;
133
  }
134
135
  /*
136
   * @param route_name string  requires
137
   *  - a valid AltoRouter route name
138
   *  - OR a Descendant of Model
139
   * @route_params requires
140
   *  - an assoc_array of url params (strongly AltoRouter-based)
141
   * returns: something to put in a href="", action="" or header('Location:');
142
   */
143
  public function prehop($route, $route_params=[])
144
  {
145
    try{
146
      $url = $this->generate($route, $route_params);
147
    }catch(\Exception $e){
148
      $url = $this->prehop(self::ROUTE_HOME_NAME);
149
    }
150
151
    return $url;
152
  }
153
154
  public function prehop_here($url=null)
155
  {
156
    return $url ?? $_SERVER['REQUEST_URI'];
157
  }
158
159
  /*
160
   * @params $route is
161
   *    - empty: default is ROUTE_HOME_NAME
162
   *    - an existing route name: make url with optional [$route_params])
163
   *    - a url, go there
164
   * @params $route_params, assoc_data for url creation (i:id, a:format, ..)
165
   */
166
  public function hop($route=null, $route_params=[])
167
  {
168
    $url = null;
169
170
    if(is_null($route))
171
      $url = $this->prehop(self::ROUTE_HOME_NAME, $route_params);
172
    elseif(is_string($route) && $this->route_exists($route))
173
      $url = $this->prehop($route, $route_params);
174
    else
175
      $url = $route;
176
177
    $this->hop_url($url);
178
  }
179
180
  // hops back to previous page (referer()), or home if no referer
181
  public function hop_back()
182
  {
183
    if(!is_null($back = $this->referer()))
184
      $this->hop_url($back);
185
186
    $this->hop();
187
  }
188
189
  public function hop_url($url)
190
  {
191
  	header('Cache-Control: no-cache, must-revalidate');
192
  	header('Expires: Mon, 01 Jan 1970 00:00:00 GMT');
193
    header('Location: '.$url);
194
    exit();
195
  }
196
197
  // returns full URL of the refering URL
198
  // returns null if same as current URL (prevents endless redirection loop)
199
  public function referer()
200
  {
201
    if(isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] != $this->web_host() .$_SERVER['REQUEST_URI'])
202
      return $_SERVER['HTTP_REFERER'];
203
204
    return null;
205
  }
206
207
  public function send_file($file_path)
208
  {
209
    if(!file_exists($file_path))
210
      throw new RouterException('SENDING_NON_EXISTING_FILE');
211
212
    $file_name = basename($file_path);
213
214
    //Get file type and set it as Content Type
215
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
216
217
    header('Content-Type: ' . finfo_file($finfo, $file_path));
218
219
    finfo_close($finfo);
220
221
    //Use Content-Disposition: attachment to specify the filename
222
    header('Content-Disposition: attachment; filename='.$file_name);
223
224
    //No cache
225
    header('Expires: 0');
226
    header('Cache-Control: must-revalidate');
227
    header('Pragma: public');
228
229
    //Define file size
230
    header('Content-Length: ' . filesize($file_path));
231
232
    ob_clean();
233
    flush();
234
    readfile($file_path);
235
    die;
236
  }
237
238
  // ----------------------------------------------------------- PROCESSING REQUESTS
239
  public function requests() : bool
240
  {
241
    return $_SERVER['REQUEST_METHOD'] === self::REQUEST_GET;
242
  }
243
244
  public function submits() : bool
245
  {
246
    return $_SERVER['REQUEST_METHOD'] === self::REQUEST_POST;
247
  }
248
249
  public function web_host() : string
250
  {
251
    return $_SERVER['REQUEST_SCHEME'].'://'.$_SERVER['HTTP_HOST'];
252
  }
253
254
  public function web_root() : string
255
  {
256
    return $this->web_host() . $this->web_base();
257
  }
258
259
  public function web_base() : string
260
  {
261
    return $this->basePath ?? '';
262
  }
263
264
  public function set_web_base($setter)
265
  {
266
    $this->setBasePath($setter);
267
  }
268
269
  public function file_root() : string
270
  {
271
    return $this->file_root ?? __DIR__;
272
  }
273
274
  public function set_file_root($setter)
275
  {
276
    $this->file_root = realpath($setter).'/';
277
  }
278
279
}
280