Elgg  Version master
RouteRegistrationService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Router;
4 
12 use Elgg\Traits\Loggable;
13 
20 
21  use Loggable;
22 
32  public function __construct(
33  protected EventsService $events,
34  protected RouteCollection $routes,
35  protected UrlGenerator $generator,
36  protected SessionManagerService $session_manager,
37  protected Plugins $plugins
38  ) {
39  }
40 
64  public function register(string $name, array $params = []): ?Route {
65 
66  $params = $this->events->triggerResults('route:config', $name, $params, $params);
67 
68  $path = elgg_extract('path', $params);
69  $controller = elgg_extract('controller', $params);
70  $file = elgg_extract('file', $params);
71  $resource = elgg_extract('resource', $params);
72  $handler = elgg_extract('handler', $params);
73  $middleware = elgg_extract('middleware', $params, []);
74  $walled = elgg_extract('walled', $params, true);
75  $deprecated = elgg_extract('deprecated', $params, '');
76  $required_plugins = (array) elgg_extract('required_plugins', $params, []);
77  $use_logged_in = (bool) elgg_extract('use_logged_in', $params, false);
78  $detect_page_owner = (bool) elgg_extract('detect_page_owner', $params, $use_logged_in);
79  $priority = (int) elgg_extract('priority', $params);
80  $options = array_merge((array) elgg_extract('options', $params, []), ['utf8' => true]);
81 
82  if (!$path || (!$controller && !$resource && !$handler && !$file)) {
83  throw new InvalidArgumentException(
84  __METHOD__ . ' requires "path" and one of controller parameters ("resource", "controller", "file" or "handler") to be set'
85  );
86  }
87 
88  foreach ($required_plugins as $plugin_id) {
89  if (!$this->plugins->isActive($plugin_id)) {
90  return null;
91  }
92  }
93 
94  $defaults = elgg_extract('defaults', $params, []);
95  $requirements = elgg_extract('requirements', $params, []);
96  $methods = elgg_extract('methods', $params, []);
97 
98  $path = trim($path, '/');
99 
100  // check if defaults should be populated with logged in user data
101  $user = $this->session_manager->getLoggedInUser();
102  if ($use_logged_in && $user instanceof \ElggUser) {
103  if (preg_match('/\{username\??\}/i', $path)) {
104  $defaults['username'] = $defaults['username'] ?? $user->username;
105  }
106 
107  if (preg_match('/\{guid\??\}/i', $path)) {
108  $defaults['guid'] = $defaults['guid'] ?? $user->guid;
109  }
110  }
111 
112  $patterns = [
113  'guid' => '\d+',
114  'group_guid' => '\d+',
115  'container_guid' => '\d+',
116  'owner_guid' => '\d+',
117  'username' => '[\p{L}\p{M}\p{Nd}._-]+',
118  ];
119 
120  $segments = explode('/', $path);
121  foreach ($segments as &$segment) {
122  // look for segments that are defined as optional with added ?
123  // e.g. /blog/owner/{username?}
124 
125  $matches = [];
126  if (!preg_match('/\{(\w*)(\?)?\}/i', $segment, $matches)) {
127  continue;
128  }
129 
130  $wildcard = $matches[1];
131  if (!isset($defaults[$wildcard]) && isset($matches[2])) {
132  $defaults[$wildcard] = ''; // make it optional
133  }
134 
135  if (!isset($requirements[$wildcard])) {
136  if (array_key_exists($wildcard, $patterns)) {
137  $requirements[$wildcard] = $patterns[$wildcard];
138  } else {
139  $requirements[$wildcard] = '.+?';
140  }
141  }
142 
143  $segment = '{' . $wildcard . '}';
144  }
145 
146  $path = '/' . implode('/', $segments);
147 
148  if ($walled !== false) {
149  $middleware[] = WalledGarden::class;
150  }
151 
152  if (!empty($options['group_tool'])) {
153  $middleware[] = GroupToolGatekeeper::class;
154  }
155 
156  $middleware[] = MaintenanceGatekeeper::class;
157 
158  $defaults['_controller'] = $controller;
159  $defaults['_file'] = $file;
160  $defaults['_resource'] = $resource;
161  $defaults['_handler'] = $handler;
162  $defaults['_deprecated'] = $deprecated;
163  $defaults['_middleware'] = $middleware;
164  $defaults['_detect_page_owner'] = $detect_page_owner;
165  $defaults['_use_logged_in'] = $use_logged_in;
166 
167  $route = new Route($path, $defaults, $requirements, $options, '', [], $methods);
168 
169  $this->routes->add($name, $route, $priority);
170 
171  return $route;
172  }
173 
181  public function unregister(string $name): void {
182  $this->routes->remove($name);
183  }
184 
192  public function get(string $name): ?Route {
193  return $this->routes->get($name);
194  }
195 
200  public function all(): array {
201  return $this->routes->all();
202  }
203 
212  public function generateUrl(string $name, array $parameters = []): ?string {
213  try {
214  $route = $this->get($name);
215  if ($route instanceof Route) {
216  $deprecated = $route->getDefault('_deprecated');
217  if (!empty($deprecated)) {
218  elgg_deprecated_notice("The route \"{$name}\" has been deprecated.", $deprecated);
219  }
220 
221  foreach ($parameters as $param_key => $value) {
222  if ($value !== null && $route->getDefault($param_key) !== null) {
223  // remove from defaults to force existence in url generation in case the param matches the default
224  $route->setDefault($param_key, null);
225  }
226  }
227  }
228 
229  $url = $this->generator->generate($name, $parameters, UrlGenerator::ABSOLUTE_URL);
230 
231  // make sure the url is always normalized so it is also usable in CLI
232  return elgg_normalize_url($url);
233  } catch (\Exception $exception) {
234  $this->getLogger()->notice($exception->getMessage());
235  }
236 
237  return null;
238  }
239 
249  public function resolveRouteParameters(string $name, ?\ElggEntity $entity = null, array $parameters = []) {
250  $route = $this->routes->get($name);
251  if (!$route) {
252  return false;
253  }
254 
255  $requirements = $route->getRequirements();
256  $defaults = $route->getDefaults();
257  $props = array_merge(array_keys($requirements), array_keys($defaults));
258 
259  foreach ($props as $prop) {
260  if (str_starts_with($prop, '_')) {
261  continue;
262  }
263 
264  if (isset($parameters[$prop])) {
265  continue;
266  }
267 
268  if (!$entity) {
269  $parameters[$prop] = '';
270  continue;
271  }
272 
273  switch ($prop) {
274  case 'title':
275  case 'name':
276  $parameters[$prop] = elgg_get_friendly_title($entity->getDisplayName());
277  break;
278 
279  default:
280  $parameters[$prop] = $entity->$prop;
281  break;
282  }
283  }
284 
285  return $parameters;
286  }
287 }
$entity
Definition: reset.php:8
if(! $user||! $user->canDelete()) $name
Definition: delete.php:22
$plugin_id
Remove all user and plugin settings from the give plugin ID.
Definition: remove.php:8
$params
Saves global plugin settings.
Definition: save.php:13
$handler
Definition: add.php:7
return[ 'admin/delete_admin_notices'=>['access'=> 'admin'], 'admin/menu/save'=>['access'=> 'admin'], 'admin/plugins/activate'=>['access'=> 'admin'], 'admin/plugins/activate_all'=>['access'=> 'admin'], 'admin/plugins/deactivate'=>['access'=> 'admin'], 'admin/plugins/deactivate_all'=>['access'=> 'admin'], 'admin/plugins/set_priority'=>['access'=> 'admin'], 'admin/security/security_txt'=>['access'=> 'admin'], 'admin/security/settings'=>['access'=> 'admin'], 'admin/security/regenerate_site_secret'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['access'=> 'admin'], 'admin/site/flush_cache'=>['access'=> 'admin'], 'admin/site/icons'=>['access'=> 'admin'], 'admin/site/set_maintenance_mode'=>['access'=> 'admin'], 'admin/site/set_robots'=>['access'=> 'admin'], 'admin/site/theme'=>['access'=> 'admin'], 'admin/site/unlock_upgrade'=>['access'=> 'admin'], 'admin/site/settings'=>['access'=> 'admin'], 'admin/upgrade'=>['access'=> 'admin'], 'admin/upgrade/reset'=>['access'=> 'admin'], 'admin/user/ban'=>['access'=> 'admin'], 'admin/user/bulk/ban'=>['access'=> 'admin'], 'admin/user/bulk/delete'=>['access'=> 'admin'], 'admin/user/bulk/unban'=>['access'=> 'admin'], 'admin/user/bulk/validate'=>['access'=> 'admin'], 'admin/user/change_email'=>['access'=> 'admin'], 'admin/user/delete'=>['access'=> 'admin'], 'admin/user/login_as'=>['access'=> 'admin'], 'admin/user/logout_as'=>[], 'admin/user/makeadmin'=>['access'=> 'admin'], 'admin/user/resetpassword'=>['access'=> 'admin'], 'admin/user/removeadmin'=>['access'=> 'admin'], 'admin/user/unban'=>['access'=> 'admin'], 'admin/user/validate'=>['access'=> 'admin'], 'annotation/delete'=>[], 'avatar/upload'=>[], 'comment/save'=>[], 'diagnostics/download'=>['access'=> 'admin'], 'entity/chooserestoredestination'=>[], 'entity/delete'=>[], 'entity/mute'=>[], 'entity/restore'=>[], 'entity/subscribe'=>[], 'entity/trash'=>[], 'entity/unmute'=>[], 'entity/unsubscribe'=>[], 'login'=>['access'=> 'logged_out'], 'logout'=>[], 'notifications/mute'=>['access'=> 'public'], 'plugins/settings/remove'=>['access'=> 'admin'], 'plugins/settings/save'=>['access'=> 'admin'], 'plugins/usersettings/save'=>[], 'register'=>['access'=> 'logged_out', 'middleware'=>[\Elgg\Router\Middleware\RegistrationAllowedGatekeeper::class,],], 'river/delete'=>[], 'settings/notifications'=>[], 'settings/notifications/subscriptions'=>[], 'user/changepassword'=>['access'=> 'public'], 'user/requestnewpassword'=>['access'=> 'public'], 'useradd'=>['access'=> 'admin'], 'usersettings/save'=>[], 'widgets/add'=>[], 'widgets/delete'=>[], 'widgets/move'=>[], 'widgets/save'=>[],]
Definition: actions.php:73
$user
Definition: ban.php:7
Persistent, installation-wide key-value storage.
Definition: Plugins.php:27
Events service.
Exception thrown if an argument is not of the expected type.
Check if the current route has a group_tool configured and that the group tool is enabled for the (gr...
Protects a route if site is in maintenance mode.
Protects a route from non-authenticated users in a walled garden mode.
RouteCollection Wrapper.
resolveRouteParameters(string $name, ?\ElggEntity $entity=null, array $parameters=[])
Populates route parameters from entity properties.
generateUrl(string $name, array $parameters=[])
Generate a absolute URL for a named route.
unregister(string $name)
Unregister a route by its name.
__construct(protected EventsService $events, protected RouteCollection $routes, protected UrlGenerator $generator, protected SessionManagerService $session_manager, protected Plugins $plugins)
Constructor.
Route Wrapper.
Definition: Route.php:8
UrlGenerator Wrapper.
Delegates requests to controllers based on the registered configuration.
Definition: Router.php:25
if($who_can_change_language==='nobody') elseif($who_can_change_language==='admin_only' &&!elgg_is_admin_logged_in()) $options
Definition: language.php:20
foreach($plugin_guids as $guid) if(empty($deactivated_plugins)) $url
Definition: deactivate.php:39
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:107
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:246
$defaults
Generic entity header upload helper.
Definition: header.php:6
$value
Definition: generic.php:51
try
Definition: login_as.php:33
$resource
$path
Definition: details.php:70
elgg_normalize_url(string $url)
Definition: output.php:163
elgg_get_friendly_title(string $title)
When given a title, returns a version suitable for inclusion in a URL.
Definition: output.php:192
$exception
Definition: error.php:15
$priority
$methods
Definition: subscribe.php:8
$segments
Definition: admin.php:13