* @since 1.0.0 */ private array $routes = []; /** * Add routes from file. * * Files need to return a php array of the following structure (see PermissionHandlingTrait): * return [ * '{REGEX_PATH}' => [ * 'dest' => '{DESTINATION_NAMESPACE:method}', // use :: for static functions * 'permission' => [ // optional * 'module' => '{NAME}', * 'type' => PermissionType::{TYPE}, * 'category' => PermissionCategory::{STATE}, * ], * // define different destination for different verb * ], * // define another regex path, destination, permission here * ]; * * @param string $path Route file path * * @return bool * * @since 1.0.0 */ public function importFromFile(string $path) : bool { if (!\is_file($path)) { return false; } /** @noinspection PhpIncludeInspection */ $this->routes += include $path; return true; } /** * Clear routes * * @return void * @since 1.0.0 */ public function clear() : void { $this->routes = []; } /** * Add route. * * @param string $route Route regex * @param mixed $destination Destination e.g. Module:function string or callback * @param int $verb Request verb * @param array $validation Validation patterns * @param string $dataPattern Data patterns * * @return void * * @since 1.0.0 */ public function add( string $route, mixed $destination, int $verb = RouteVerb::GET, array $validation = [], string $dataPattern = '' ) : void { if (!isset($this->routes[$route])) { $this->routes[$route] = []; } $this->routes[$route][] = [ 'dest' => $destination, 'verb' => $verb, 'validation' => empty($validation) ? null : $validation, 'pattern' => empty($dataPattern) ? null : $dataPattern, ]; } /** * Route request. * * @param string $uri Route * @param int $verb Route verb * @param string $app Application name * @param int $orgId Organization id * @param Account $account Account * @param array $data Data * * @return array[] * * @since 1.0.0 */ public function route( string $uri, int $verb = RouteVerb::GET, string $app = null, int $orgId = null, Account $account = null, array $data = null ) : array { $bound = []; foreach ($this->routes as $route => $destination) { if (!((bool) \preg_match('~^' . $route . '$~', $uri))) { continue; } foreach ($destination as $d) { if ((!isset($d['verb']) || $d['verb'] === RouteVerb::ANY) || $verb === RouteVerb::ANY || ($verb & $d['verb']) === $verb ) { // if permission check is invalid if (isset($d['permission']) && !empty($d['permission']) && ($account === null || $account instanceof NullAccount) ) { return ['dest' => RouteStatus::NOT_LOGGED_IN]; } elseif (isset($d['permission']) && !empty($d['permission']) && !($account?->hasPermission( $d['permission']['type'] ?? 0, $d['permission']['unit'] ?? $orgId, $app, $d['permission']['module'] ?? null, $d['permission']['category'] ?? null ) ) ) { return ['dest' => RouteStatus::INVALID_PERMISSIONS]; } // if validation check is invalid if (isset($d['validation'])) { foreach ($d['validation'] as $name => $pattern) { if (!isset($data[$name]) || \preg_match($pattern, $data[$name]) !== 1) { return ['dest' => RouteStatus::INVALID_DATA]; } } } $temp = ['dest' => $d['dest']]; // fill data if (isset($d['pattern'])) { \preg_match($d['pattern'], $uri, $matches); $temp['data'] = $matches; } $bound[] = $temp; } } } return $bound; } }