Elgg  Version master
RouteRegistrationService.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Router;
4 
10 
17 
18  use Loggable;
19 
23  protected $events;
24 
28  protected $routes;
29 
33  protected $generator;
34 
42  public function __construct(
46  ) {
47  $this->events = $events;
48  $this->routes = $routes;
49  $this->generator = $generator;
50  }
51 
74  public function register(string $name, array $params = []): Route {
75 
76  $params = $this->events->triggerResults('route:config', $name, $params, $params);
77 
78  $path = elgg_extract('path', $params);
79  $controller = elgg_extract('controller', $params);
80  $file = elgg_extract('file', $params);
81  $resource = elgg_extract('resource', $params);
82  $handler = elgg_extract('handler', $params);
83  $middleware = elgg_extract('middleware', $params, []);
84  $walled = elgg_extract('walled', $params, true);
85  $deprecated = elgg_extract('deprecated', $params, '');
86  $required_plugins = elgg_extract('required_plugins', $params, []);
87  $detect_page_owner = (bool) elgg_extract('detect_page_owner', $params, false);
88  $priority = (int) elgg_extract('priority', $params);
89 
90  if (!$path || (!$controller && !$resource && !$handler && !$file)) {
91  throw new InvalidArgumentException(
92  __METHOD__ . ' requires "path" and one of controller parameters ("resource", "controller", "file" or "handler") to be set'
93  );
94  }
95 
96  $defaults = elgg_extract('defaults', $params, []);
97  $requirements = elgg_extract('requirements', $params, []);
98  $methods = elgg_extract('methods', $params, []);
99 
100  $patterns = [
101  'guid' => '\d+',
102  'group_guid' => '\d+',
103  'container_guid' => '\d+',
104  'owner_guid' => '\d+',
105  'username' => '[\p{L}\p{M}\p{Nd}._-]+',
106  ];
107 
108  $path = trim($path, '/');
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 
152  $route = new Route($path, $defaults, $requirements, [
153  'utf8' => true,
154  ], '', [], $methods);
155 
156  $this->routes->add($name, $route, $priority);
157 
158  return $route;
159  }
160 
168  public function unregister(string $name): void {
169  $this->routes->remove($name);
170  }
171 
179  public function get(string $name): ?Route {
180  return $this->routes->get($name);
181  }
182 
187  public function all(): array {
188  return $this->routes->all();
189  }
190 
199  public function generateUrl(string $name, array $parameters = []): ?string {
200  try {
201  $route = $this->get($name);
202  if ($route instanceof Route) {
203  $deprecated = $route->getDefault('_deprecated');
204  if (!empty($deprecated)) {
205  elgg_deprecated_notice("The route \"{$name}\" has been deprecated.", $deprecated);
206  }
207  }
208 
209  $url = $this->generator->generate($name, $parameters, UrlGenerator::ABSOLUTE_URL);
210 
211  // make sure the url is always normalized so it is also usable in CLI
212  return elgg_normalize_url($url);
213  } catch (\Exception $exception) {
214  $this->getLogger()->notice($exception->getMessage());
215  }
216 
217  return null;
218  }
219 
229  public function resolveRouteParameters(string $name, \ElggEntity $entity = null, array $parameters = []) {
230  $route = $this->routes->get($name);
231  if (!$route) {
232  return false;
233  }
234 
235  $requirements = $route->getRequirements();
236  $defaults = $route->getDefaults();
237  $props = array_merge(array_keys($requirements), array_keys($defaults));
238 
239  foreach ($props as $prop) {
240  if (str_starts_with($prop, '_')) {
241  continue;
242  }
243 
244  if (isset($parameters[$prop])) {
245  continue;
246  }
247 
248  if (!$entity) {
249  $parameters[$prop] = '';
250  continue;
251  }
252 
253  switch ($prop) {
254  case 'title':
255  case 'name':
256  $parameters[$prop] = elgg_get_friendly_title($entity->getDisplayName());
257  break;
258 
259  default:
260  $parameters[$prop] = $entity->$prop;
261  break;
262  }
263  }
264 
265  return $parameters;
266  }
267 }
Exception thrown if an argument is not of the expected type.
$params
Saves global plugin settings.
Definition: save.php:13
__construct(EventsService $events, RouteCollection $routes, UrlGenerator $generator)
Constructor.
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: elgglib.php:115
$defaults
Generic entity header upload helper.
Definition: header.php:6
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is void
Definition: LICENSE.txt:215
Events service.
$resource
generateUrl(string $name, array $parameters=[])
Generate a absolute URL for a named route.
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:254
$path
Definition: details.php:70
trait Loggable
Enables adding a logger.
Definition: Loggable.php:14
unregister(string $name)
Unregister a route by its name.
Route Wrapper.
Definition: Route.php:8
$entity
Definition: reset.php:8
elgg_get_friendly_title(string $title)
When given a title, returns a version suitable for inclusion in a URL.
Definition: output.php:192
getLogger()
Returns logger.
Definition: Loggable.php:37
RouteCollection Wrapper.
$exception
Definition: error.php:15
resolveRouteParameters(string $name,\ElggEntity $entity=null, array $parameters=[])
Populates route parameters from entity properties.
foreach($plugin_guids as $guid) if(empty($deactivated_plugins)) $url
Definition: deactivate.php:39
$segments
Definition: admin.php:13
$handler
Definition: add.php:7
elgg_normalize_url(string $url)
Definition: output.php:163
$methods
Definition: subscribe.php:8
$priority
UrlGenerator Wrapper.