Elgg  Version 6.3
Router.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg;
4 
9 use Elgg\Http\Request as HttpRequest;
15 use Symfony\Component\Routing\Exception\MethodNotAllowedException;
16 use Symfony\Component\Routing\Exception\ResourceNotFoundException;
17 
26 class Router {
27 
28  use Profilable;
29 
40  public function __construct(
41  protected EventsService $events,
42  protected RouteCollection $routes,
43  protected UrlMatcher $matcher,
44  protected HandlersService $handlers,
45  protected ResponseFactory $response,
46  protected Plugins $plugins
47  ) {
48  }
49 
60  public function route(HttpRequest $request): bool {
61  $this->beginTimer(['build page']);
62 
63  $request->validate();
64 
65  $response = $this->getResponse($request);
66 
67  if ($this->response->getSentResponse()) {
68  return true;
69  }
70 
71  $this->response->respond($response);
72 
73  return headers_sent();
74  }
75 
84  public function getResponse(HttpRequest $request) {
85  $response = $this->prepareResponse($request);
86 
87  if (!$response instanceof ResponseBuilder) {
88  throw new PageNotFoundException();
89  }
90 
91  if ($request->getFirstUrlSegment() == 'action') {
92  if ($response->getForwardURL() === null) {
93  $response->setForwardURL(REFERRER);
94  }
95  }
96 
97  return $response;
98  }
99 
109  protected function prepareResponse(HttpRequest $request) {
110 
111  $segments = $request->getUrlSegments();
112  $path = '/' . implode('/', $segments);
113 
114  try {
115  $parameters = $this->matcher->match($path);
116 
117  $resource = (string) elgg_extract('_resource', $parameters);
118  unset($parameters['_resource']);
119 
120  $handler = elgg_extract('_handler', $parameters);
121  unset($parameters['_handler']);
122 
123  $controller = elgg_extract('_controller', $parameters);
124  unset($parameters['_controller']);
125 
126  $file = elgg_extract('_file', $parameters);
127  unset($parameters['_file']);
128 
129  $deprecated = elgg_extract('_deprecated', $parameters, '');
130  unset($parameters['_deprecated']);
131 
132  $middleware = elgg_extract('_middleware', $parameters, []);
133  unset($parameters['_middleware']);
134 
135  $required_plugins = (array) elgg_extract('_required_plugins', $parameters, []);
136  unset($parameters['_required_plugins']);
137 
138  unset($parameters['_detect_page_owner']);
139  unset($parameters['_use_logged_in']);
140 
141  foreach ($required_plugins as $plugin_id) {
142  if (!$this->plugins->isActive($plugin_id)) {
143  throw new PageNotFoundException();
144  }
145  }
146 
147  $route = $this->routes->get($parameters['_route']);
148  $route->setMatchedParameters($parameters);
149  $request->setRoute($route);
150 
151  $envelope = new \Elgg\Request(elgg(), $request);
152  $parameters['request'] = $envelope;
153 
154  if (!empty($deprecated)) {
155  elgg_deprecated_notice("The route \"{$route->getName()}\" has been deprecated.", $deprecated);
156  }
157 
158  foreach ($middleware as $callable) {
159  $result = $this->handlers->call($callable, $envelope, null);
160  if ($result[1] instanceof ResponseBuilder) {
161  return $result[1];
162  }
163  }
164 
165  if ($handler) {
166  return $this->getResponseFromHandler($handler, $envelope);
167  } elseif ($controller) {
168  $result = $this->handlers->call($controller, $envelope, null);
169  if ($result[1] instanceof ResponseBuilder) {
170  return $result[1];
171  }
172  } elseif ($file) {
173  return $this->getResponseFromFile($file, $envelope);
174  }
175 
176  $output = elgg_view_resource($resource, $parameters);
177  return elgg_ok_response($output);
178  } catch (ResourceNotFoundException $ex) {
179  throw new PageNotFoundException();
180  } catch (MethodNotAllowedException $ex) {
181  throw new BadRequestException();
182  }
183  }
184 
194  if (!is_callable($handler)) {
195  return null;
196  }
197 
198  $path = trim($request->getPath(), '/');
199  $segments = explode('/', $path);
200  $identifier = array_shift($segments) ?: '';
201 
202  ob_start();
203  try {
204  $response = call_user_func($handler, $segments, $identifier, $request);
205  } catch (\Exception $ex) {
206  ob_end_clean();
207  throw $ex;
208  }
209 
210  $output = ob_get_clean();
211 
212  if ($response instanceof ResponseBuilder) {
213  return $response;
214  } else if ($response === false) {
215  return null;
216  }
217 
218  return elgg_ok_response($output);
219  }
220 
230  protected function getResponseFromFile(string $file, \Elgg\Request $request) {
231  if (!is_file($file)) {
232  throw new PageNotFoundException(elgg_echo('actionnotfound', [$request->getPath()]), ELGG_HTTP_NOT_IMPLEMENTED);
233  }
234 
235  ob_start();
236 
237  try {
238  $response = include $file;
239  } catch (\Exception $ex) {
240  ob_get_clean();
241  throw $ex;
242  }
243 
244  $output = ob_get_clean();
245 
246  if ($response instanceof ResponseBuilder) {
247  return $response;
248  }
249 
250  return elgg_ok_response($output);
251  }
252 
261  public function allowRewrite(HttpRequest $request) {
262  $segments = $request->getUrlSegments();
263  if (!empty($segments)) {
264  $identifier = array_shift($segments);
265  } else {
266  $identifier = '';
267  }
268 
269  $old = [
270  'identifier' => $identifier,
271  'segments' => $segments,
272  ];
273  $new = $this->events->triggerResults('route:rewrite', $identifier, $old, $old);
274  if ($new === $old) {
275  return $request;
276  }
277 
278  if (!isset($new['identifier']) ||
279  !isset($new['segments']) ||
280  !is_string($new['identifier']) ||
281  !is_array($new['segments'])
282  ) {
283  throw new RuntimeException('rewrite_path handler returned invalid route data.');
284  }
285 
286  // rewrite request
287  $segments = $new['segments'];
288  array_unshift($segments, $new['identifier']);
289 
290  return $request->setUrlSegments($segments);
291  }
292 }
$plugin_id
Remove all user and plugin settings from the give plugin ID.
Definition: remove.php:8
$handler
Definition: add.php:7
Persistent, installation-wide key-value storage.
Definition: Plugins.php:27
Events service.
Thrown when request is malformatted.
Thrown when page is not accessible.
Exception thrown if an error which can only be found on runtime occurs.
Helpers for providing callable-based APIs.
Elgg HTTP request.
Definition: Request.php:17
HTTP response service.
Request container.
Definition: Request.php:12
RouteCollection Wrapper.
UrlMatcher Wrapper.
Definition: UrlMatcher.php:8
Delegates requests to controllers based on the registered configuration.
Definition: Router.php:26
__construct(protected EventsService $events, protected RouteCollection $routes, protected UrlMatcher $matcher, protected HandlersService $handlers, protected ResponseFactory $response, protected Plugins $plugins)
Constructor.
Definition: Router.php:40
prepareResponse(HttpRequest $request)
Prepare response.
Definition: Router.php:109
getResponseFromHandler($handler, \Elgg\Request $request)
Get response from handler function.
Definition: Router.php:193
getResponseFromFile(string $file, \Elgg\Request $request)
Get response from file.
Definition: Router.php:230
route(HttpRequest $request)
Routes the request to a registered page handler.
Definition: Router.php:60
getResponse(HttpRequest $request)
Build a response.
Definition: Router.php:84
allowRewrite(HttpRequest $request)
Filter a request through the 'route:rewrite' event.
Definition: Router.php:261
const ELGG_HTTP_NOT_IMPLEMENTED
Definition: constants.php:92
const REFERRER
Used in calls to forward() to specify the browser should be redirected to the referring page.
Definition: constants.php:37
if($item instanceof \ElggEntity) elseif($item instanceof \ElggRiverItem) elseif($item instanceof \ElggRelationship) elseif(is_callable([ $item, 'getType']))
Definition: item.php:48
$output
Definition: download.php:9
elgg()
Bootstrapping and helper procedural code available for use in Elgg core and plugins.
Definition: elgglib.php:12
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:101
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:240
HTTP response builder interface.
elgg_echo(string $message_key, array $args=[], string $language='')
Elgg language module Functions to manage language and translations.
Definition: languages.php:17
elgg_view_resource(string $name, array $vars=[])
Render a resource view.
Definition: views.php:307
$request
Definition: livesearch.php:12
$resource
trait Profilable
Make an object accept a timer.
Definition: Profilable.php:12
beginTimer(array $keys)
Start the timer (when enabled)
Definition: Profilable.php:43
$path
Definition: details.php:70
elgg_ok_response($content='', string|array $message='', ?string $forward_url=null, int $status_code=ELGG_HTTP_OK)
Prepares a successful response to be returned by a page or an action handler.
$segments
Definition: admin.php:13
$response
Definition: content.php:10