3 // Copyright (c) 2015 Blue Static
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or any later version.
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 // You should have received a copy of the GNU General Public License along with
15 // this program. If not, see <http://www.gnu.org/licenses/>.
17 namespace hoplite\http
;
19 require_once HOPLITE_ROOT
. '/http/interceptor.php';
20 require_once HOPLITE_ROOT
. '/http/request.php';
21 require_once HOPLITE_ROOT
. '/http/response.php';
22 require_once HOPLITE_ROOT
. '/http/response_code.php';
25 The FrontController is meant to be invoked from the index.php of the
31 private $request = NULL
;
34 private $response = NULL
;
37 private $url_map = NULL
;
39 /*! @var OutputFilter */
40 private $output_filter = NULL
;
42 /*! @var Array<Interceptor> */
43 private $interceptors = [];
46 Creates the controller with the request context information, typicallhy
47 from the global scope ($GLOBALS), but can be injected for testing.
48 @param array PHP globals array
50 public function __construct(array $globals)
52 $this->response
= new Response();
53 $this->request
= new Request();
54 $this->request
->data
= array(
55 '_GET' => &$globals['_GET'],
56 '_POST' => &$globals['_POST'],
57 '_COOKIE' => &$globals['_COOKIE'],
58 '_SERVER' => &$globals['_SERVER']
63 public function request() { return $this->request
; }
64 public function response() { return $this->response
; }
66 /*! Sets the UrlMap. */
67 public function set_url_map(UrlMap
$url_map) { $this->url_map
= $url_map; }
69 /*! Sest the Output Filter. */
70 public function set_output_filter(OutputFilter
$output_filter)
72 $this->output_filter
= $output_filter;
75 /*! Registers an Interceptor that will be run before executing an Action. */
76 public function AddInterceptor(Interceptor
$interceptor)
78 $this->interceptors
[] = $interceptor;
82 Called in index.php to process the current HTTP request. This initializes the
83 Request object from its data and then routes the request to generate the
86 public function ProcessRequest()
88 // The query rewriter module of the webserver rewrites a request from:
89 // http://example.com/webapp/user/view/42
91 // http://example.com/webapp/index.php/user/view/42
92 // ... which then becomes accessible from PATH_INFO.
93 $data = $this->request
->data
['_SERVER'];
94 if (isset($data['PATH_INFO']))
95 $url = $data['PATH_INFO'];
99 $url = substr($url, 1);
101 // Set the final pieces of the request.
102 $this->request
->url
= $url;
103 $this->request
->http_method
= $this->request
->data
['_SERVER']['REQUEST_METHOD'];
105 // Extract any PUT data as POST params.
106 if ($this->request
->http_method
== 'PUT')
107 parse_str(file_get_contents('php://input'), $this->request
->data
['_POST']);
109 // Register self as the active instance.
110 $GLOBALS[__CLASS__
] = $this;
112 // Dispatch the request to an Action.
113 $this->RouteRequest($this->request
);
115 // When control returns here, all actions have been invoked and it's time
116 // to start the output filter and exit.
117 $this->SendResponse();
121 Prevents any other Actions from executing. This starts the OutputFilter and
124 public function SendResponse()
126 $this->output_filter
->FilterOutput($this->request
, $this->response
);
131 Sets the response code and stops the controller. Returns void.
133 public function SendResponseCode($code)
135 $this->response
->response_code
= $code;
136 $this->SendResponse();
140 Sets the response code to HTTP 302 FOUND and redirects the page to a new
142 @param string The destination location of the redirect.
144 public function SendResponseRedirect($location)
146 $this->response
->headers
['Location'] = $location;
147 $this->SendResponseCode(ResponseCode
::FOUND
);
151 Wrapper around PHP exit().
153 protected function _Exit()
159 Given an Request object, this executes the action for the corresponding URL.
160 The action is located by performing a lookup in the UrlMap. Interceptors
161 are run before invoking the action.
162 @param Request The Request whose URL will be routed
164 public function RouteRequest(Request
$request)
166 $url_map_value = $this->url_map
->Evaluate($request);
170 $action = $this->url_map
->LookupAction($url_map_value);
172 foreach ($this->interceptors
as $interceptor)
173 $interceptor->DoIntercept($this, $action, $request, $this->response
);
176 $this->InvokeAction($action);
180 Invokes the action with the Controller's request and response objects.
182 public function InvokeAction(Action
$action)
184 $action->Invoke($this->request
, $this->response
);
188 Performs a reverse-lookup in the UrlMap for the pattern/fragment for the
189 name of a given Action class.
190 @param string Class name.
192 public function LookupAction($class)
194 $map = $this->url_map
->map();
195 foreach ($map as $pattern => $action) {
196 if ($action == $class)
202 Given a relative path, return an absolute path from the root controller.
203 @param string The relative path for which a URL will be created
204 @param bool Include the HTTP scheme and host to create an RFC URL if true;
205 if false an absolute path will be returned.
207 public function MakeURL($new_path, $url = FALSE
)
209 // Detect the common paths between the REQUEST_URI and the PATH_INFO. That
210 // common piece will be the path to the root controller.
211 $request_uri = $this->request()->data
['_SERVER']['REQUEST_URI'];
212 $path_info = $this->request()->data
['_SERVER']['PATH_INFO'];
213 if ($path_info === NULL
)
214 $common_uri = substr($request_uri, 0, -1);
216 $common_uri = strstr($request_uri, $path_info, TRUE
);
218 // If just constructing an absolute path, return that now.
220 return $common_uri . $new_path;
222 // Otherwise, build the host part.
224 if (isset($this->request()->data
['_SERVER']['HTTPS']) &&
225 $this->request()->data
['_SERVER']['HTTPS'] == 'on') {
228 $url .= '://' . $this->request()->data
['_SERVER']['HTTP_HOST'];
230 $port = $this->request()->data
['_SERVER']['SERVER_PORT'];
231 if ($port != 80 && $port != 443)
235 return $url . $new_path;