Elgg  Version master
RouteRegistrationService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Router;
4 
10 use Elgg\Traits\Loggable;
11 
18 
19  use Loggable;
20 
29  public function __construct(
30  protected EventsService $events,
31  protected RouteCollection $routes,
32  protected UrlGenerator $generator,
33  protected SessionManagerService $session_manager
34  ) {
35  }
36 
60  public function register(string $name, array $params = []): Route {
61 
62  $params = $this->events->triggerResults('route:config', $name, $params, $params);
63 
64  $path = elgg_extract('path', $params);
65  $controller = elgg_extract('controller', $params);
66  $file = elgg_extract('file', $params);
67  $resource = elgg_extract('resource', $params);
68  $handler = elgg_extract('handler', $params);
69  $middleware = elgg_extract('middleware', $params, []);
70  $walled = elgg_extract('walled', $params, true);
71  $deprecated = elgg_extract('deprecated', $params, '');
72  $required_plugins = elgg_extract('required_plugins', $params, []);
73  $use_logged_in = (bool) elgg_extract('use_logged_in', $params, false);
74  $detect_page_owner = (bool) elgg_extract('detect_page_owner', $params, $use_logged_in);
75  $priority = (int) elgg_extract('priority', $params);
76 
77  if (!$path || (!$controller && !$resource && !$handler && !$file)) {
78  throw new InvalidArgumentException(
79  __METHOD__ . ' requires "path" and one of controller parameters ("resource", "controller", "file" or "handler") to be set'
80  );
81  }
82 
83  $defaults = elgg_extract('defaults', $params, []);
84  $requirements = elgg_extract('requirements', $params, []);
85  $methods = elgg_extract('methods', $params, []);
86 
87  $path = trim($path, '/');
88 
89  // check if defaults should be populated with logged in user data
90  $user = $this->session_manager->getLoggedInUser();
91  if ($use_logged_in && $user instanceof \ElggUser) {
92  if (preg_match('/\{username\??\}/i', $path)) {
93  $defaults['username'] = $defaults['username'] ?? $user->username;
94  }
95 
96  if (preg_match('/\{guid\??\}/i', $path)) {
97  $defaults['guid'] = $defaults['guid'] ?? $user->guid;
98  }
99  }
100 
101  $patterns = [
102  'guid' => '\d+',
103  'group_guid' => '\d+',
104  'container_guid' => '\d+',
105  'owner_guid' => '\d+',
106  'username' => '[\p{L}\p{M}\p{Nd}._-]+',
107  ];
108 
109  $segments = explode('/', $path);
110  foreach ($segments as &$segment) {
111  // look for segments that are defined as optional with added ?
112  // e.g. /blog/owner/{username?}
113 
114  $matches = [];
115  if (!preg_match('/\{(\w*)(\?)?\}/i', $segment, $matches)) {
116  continue;
117  }
118 
119  $wildcard = $matches[1];
120  if (!isset($defaults[$wildcard]) && isset($matches[2])) {
121  $defaults[$wildcard] = ''; // make it optional
122  }
123 
124  if (!isset($requirements[$wildcard])) {
125  if (array_key_exists($wildcard, $patterns)) {
126  $requirements[$wildcard] = $patterns[$wildcard];
127  } else {
128  $requirements[$wildcard] = '.+?';
129  }
130  }
131 
132  $segment = '{' . $wildcard . '}';
133  }
134 
135  $path = '/' . implode('/', $segments);
136 
137  if ($walled !== false) {
138  $middleware[] = WalledGarden::class;
139  }
140 
141  $middleware[] = MaintenanceGatekeeper::class;
142 
143  $defaults['_controller'] = $controller;
144  $defaults['_file'] = $file;
145  $defaults['_resource'] = $resource;
146  $defaults['_handler'] = $handler;
147  $defaults['_deprecated'] = $deprecated;
148  $defaults['_middleware'] = $middleware;
149  $defaults['_required_plugins'] = $required_plugins;
150  $defaults['_detect_page_owner'] = $detect_page_owner;
151  $defaults['_use_logged_in'] = $use_logged_in;
152 
153  $options = array_merge((array) elgg_extract('options', $params, []), ['utf8' => true]);
154 
155  $route = new Route($path, $defaults, $requirements, $options, '', [], $methods);
156 
157  $this->routes->add($name, $route, $priority);
158 
159  return $route;
160  }
161 
169  public function unregister(string $name): void {
170  $this->routes->remove($name);
171  }
172 
180  public function get(string $name): ?Route {
181  return $this->routes->get($name);
182  }
183 
188  public function all(): array {
189  return $this->routes->all();
190  }
191 
200  public function generateUrl(string $name, array $parameters = []): ?string {
201  try {
202  $route = $this->get($name);
203  if ($route instanceof Route) {
204  $deprecated = $route->getDefault('_deprecated');
205  if (!empty($deprecated)) {
206  elgg_deprecated_notice("The route \"{$name}\" has been deprecated.", $deprecated);
207  }
208 
209  foreach ($parameters as $param_key => $value) {
210  if ($value !== null && $route->getDefault($param_key) !== null) {
211  // remove from defaults to force existence in url generation in case the param matches the default
212  $route->setDefault($param_key, null);
213  }
214  }
215  }
216 
217  $url = $this->generator->generate($name, $parameters, UrlGenerator::ABSOLUTE_URL);
218 
219  // make sure the url is always normalized so it is also usable in CLI
220  return elgg_normalize_url($url);
221  } catch (\Exception $exception) {
222  $this->getLogger()->notice($exception->getMessage());
223  }
224 
225  return null;
226  }
227 
237  public function resolveRouteParameters(string $name, ?\ElggEntity $entity = null, array $parameters = []) {
238  $route = $this->routes->get($name);
239  if (!$route) {
240  return false;
241  }
242 
243  $requirements = $route->getRequirements();
244  $defaults = $route->getDefaults();
245  $props = array_merge(array_keys($requirements), array_keys($defaults));
246 
247  foreach ($props as $prop) {
248  if (str_starts_with($prop, '_')) {
249  continue;
250  }
251 
252  if (isset($parameters[$prop])) {
253  continue;
254  }
255 
256  if (!$entity) {
257  $parameters[$prop] = '';
258  continue;
259  }
260 
261  switch ($prop) {
262  case 'title':
263  case 'name':
264  $parameters[$prop] = elgg_get_friendly_title($entity->getDisplayName());
265  break;
266 
267  default:
268  $parameters[$prop] = $entity->$prop;
269  break;
270  }
271  }
272 
273  return $parameters;
274  }
275 }
$entity
Definition: reset.php:8
if(! $user||! $user->canDelete()) $name
Definition: delete.php:22
$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
Events service.
Exception thrown if an argument is not of the expected type.
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.
__construct(protected EventsService $events, protected RouteCollection $routes, protected UrlGenerator $generator, protected SessionManagerService $session_manager)
Constructor.
generateUrl(string $name, array $parameters=[])
Generate a absolute URL for a named route.
unregister(string $name)
Unregister a route by its name.
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: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
$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