Elgg  Version master
RouteRegistrationService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Router;
4 
11 use Elgg\Traits\Loggable;
12 
19 
20  use Loggable;
21 
31  public function __construct(
32  protected EventsService $events,
33  protected RouteCollection $routes,
34  protected UrlGenerator $generator,
35  protected SessionManagerService $session_manager,
36  protected Plugins $plugins
37  ) {
38  }
39 
63  public function register(string $name, array $params = []): ?Route {
64 
65  $params = $this->events->triggerResults('route:config', $name, $params, $params);
66 
67  $path = elgg_extract('path', $params);
68  $controller = elgg_extract('controller', $params);
69  $file = elgg_extract('file', $params);
70  $resource = elgg_extract('resource', $params);
71  $handler = elgg_extract('handler', $params);
72  $middleware = elgg_extract('middleware', $params, []);
73  $walled = elgg_extract('walled', $params, true);
74  $deprecated = elgg_extract('deprecated', $params, '');
75  $required_plugins = (array) elgg_extract('required_plugins', $params, []);
76  $use_logged_in = (bool) elgg_extract('use_logged_in', $params, false);
77  $detect_page_owner = (bool) elgg_extract('detect_page_owner', $params, $use_logged_in);
78  $priority = (int) elgg_extract('priority', $params);
79  $options = array_merge((array) elgg_extract('options', $params, []), ['utf8' => true]);
80 
81  if (!$path || (!$controller && !$resource && !$handler && !$file)) {
82  throw new InvalidArgumentException(
83  __METHOD__ . ' requires "path" and one of controller parameters ("resource", "controller", "file" or "handler") to be set'
84  );
85  }
86 
87  foreach ($required_plugins as $plugin_id) {
88  if (!$this->plugins->isActive($plugin_id)) {
89  return null;
90  }
91  }
92 
93  $defaults = elgg_extract('defaults', $params, []);
94  $requirements = elgg_extract('requirements', $params, []);
95  $methods = elgg_extract('methods', $params, []);
96 
97  $path = trim($path, '/');
98 
99  // check if defaults should be populated with logged in user data
100  $user = $this->session_manager->getLoggedInUser();
101  if ($use_logged_in && $user instanceof \ElggUser) {
102  if (preg_match('/\{username\??\}/i', $path)) {
103  $defaults['username'] = $defaults['username'] ?? $user->username;
104  }
105 
106  if (preg_match('/\{guid\??\}/i', $path)) {
107  $defaults['guid'] = $defaults['guid'] ?? $user->guid;
108  }
109  }
110 
111  $patterns = [
112  'guid' => '\d+',
113  'group_guid' => '\d+',
114  'container_guid' => '\d+',
115  'owner_guid' => '\d+',
116  'username' => '[\p{L}\p{M}\p{Nd}._-]+',
117  ];
118 
119  $segments = explode('/', $path);
120  foreach ($segments as &$segment) {
121  // look for segments that are defined as optional with added ?
122  // e.g. /blog/owner/{username?}
123 
124  $matches = [];
125  if (!preg_match('/\{(\w*)(\?)?\}/i', $segment, $matches)) {
126  continue;
127  }
128 
129  $wildcard = $matches[1];
130  if (!isset($defaults[$wildcard]) && isset($matches[2])) {
131  $defaults[$wildcard] = ''; // make it optional
132  }
133 
134  if (!isset($requirements[$wildcard])) {
135  if (array_key_exists($wildcard, $patterns)) {
136  $requirements[$wildcard] = $patterns[$wildcard];
137  } else {
138  $requirements[$wildcard] = '.+?';
139  }
140  }
141 
142  $segment = '{' . $wildcard . '}';
143  }
144 
145  $path = '/' . implode('/', $segments);
146 
147  if ($walled !== false) {
148  $middleware[] = WalledGarden::class;
149  }
150 
151  if (!empty($options['group_tool'])) {
152  $middleware[] = GroupToolGatekeeper::class;
153  }
154 
155  $defaults['_controller'] = $controller;
156  $defaults['_file'] = $file;
157  $defaults['_resource'] = $resource;
158  $defaults['_handler'] = $handler;
159  $defaults['_deprecated'] = $deprecated;
160  $defaults['_middleware'] = $middleware;
161  $defaults['_detect_page_owner'] = $detect_page_owner;
162  $defaults['_use_logged_in'] = $use_logged_in;
163 
164  $route = new Route($path, $defaults, $requirements, $options, '', [], $methods);
165 
166  $this->routes->add($name, $route, $priority);
167 
168  return $route;
169  }
170 
178  public function unregister(string $name): void {
179  $this->routes->remove($name);
180  }
181 
189  public function get(string $name): ?Route {
190  return $this->routes->get($name);
191  }
192 
197  public function all(): array {
198  return $this->routes->all();
199  }
200 
209  public function generateUrl(string $name, array $parameters = []): ?string {
210  try {
211  $route = $this->get($name);
212  if ($route instanceof Route) {
213  $deprecated = $route->getDefault('_deprecated');
214  if (!empty($deprecated)) {
215  elgg_deprecated_notice("The route \"{$name}\" has been deprecated.", $deprecated);
216  }
217 
218  foreach ($parameters as $param_key => $value) {
219  if ($value !== null && $route->getDefault($param_key) !== null) {
220  // remove from defaults to force existence in url generation in case the param matches the default
221  $route->setDefault($param_key, null);
222  }
223  }
224  }
225 
226  $url = $this->generator->generate($name, $parameters, UrlGenerator::ABSOLUTE_URL);
227 
228  // make sure the url is always normalized so it is also usable in CLI
229  return elgg_normalize_url($url);
230  } catch (\Exception $exception) {
231  $this->getLogger()->notice($exception->getMessage());
232  }
233 
234  return null;
235  }
236 
246  public function resolveRouteParameters(string $name, ?\ElggEntity $entity = null, array $parameters = []) {
247  $route = $this->routes->get($name);
248  if (!$route) {
249  return false;
250  }
251 
252  $requirements = $route->getRequirements();
253  $defaults = $route->getDefaults();
254  $props = array_merge(array_keys($requirements), array_keys($defaults));
255 
256  foreach ($props as $prop) {
257  if (str_starts_with($prop, '_')) {
258  continue;
259  }
260 
261  if (isset($parameters[$prop])) {
262  continue;
263  }
264 
265  if (!$entity) {
266  $parameters[$prop] = '';
267  continue;
268  }
269 
270  switch ($prop) {
271  case 'title':
272  case 'name':
273  $parameters[$prop] = elgg_get_friendly_title($entity->getDisplayName());
274  break;
275 
276  default:
277  $parameters[$prop] = $entity->$prop;
278  break;
279  }
280  }
281 
282  return $parameters;
283  }
284 }
$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/clear'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['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', 'controller'=> \Elgg\Diagnostics\DownloadController::class,], '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:76
$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 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:26
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