Exception:Array
(
[message] => syntax error, unexpected identifier "stringRegex", expecting "="
[file] => /home/johannes/web/transferworld.nl/public_html/system/routes.php
[line_no] => 25
[line] => const string stringRegex = '{(\w+)}'; // <==
[lines] => Array
(
[0] => * along with this program. If not, see .
[1] => *
[2] => */
[3] =>
[4] => namespace Vvveb\System;
[5] =>
[6] => class Routes {
[7] => const string stringRegex = '{(\w+)}'; // <==
[8] =>
[9] => const string varRegex = '[{#]([a-zA-Z]\w+)({([\d,]+)})?[#}]';
[10] =>
[11] => const string stringLimitRegex = '{([a-zA-Z]\w+){([\d,]+)}}';
[12] =>
[13] => const string numericRegex = '#([a-zA-Z]\w+)#';
)
[trace] => #0 /home/johannes/web/transferworld.nl/public_html/system/core/frontcontroller.php(387): Vvveb\System\Core\autoload()
#1 /home/johannes/web/transferworld.nl/public_html/system/core/startup.php(514): Vvveb\System\Core\FrontController::dispatch()
#2 /home/johannes/web/transferworld.nl/public_html/index.php(120): Vvveb\System\Core\start()
#3 /home/johannes/web/transferworld.nl/public_html/index.php(166): Vvveb\saveCache()
#4 {main}
[code] => Array
(
[0] =>
[2] => /**
[3] => * Vvveb
[4] => *
[5] => * Copyright (C) 2022 Ziadin Givan
[6] => *
[7] => * This program is free software: you can redistribute it and/or modify
[8] => * it under the terms of the GNU Affero General Public License as
[9] => * published by the Free Software Foundation, either version 3 of the
[10] => * License, or (at your option) any later version.
[11] => *
[12] => * This program is distributed in the hope that it will be useful,
[13] => * but WITHOUT ANY WARRANTY; without even the implied warranty of
[14] => * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[15] => * GNU Affero General Public License for more details.
[16] => *
[17] => * You should have received a copy of the GNU Affero General Public License
[18] => * along with this program. If not, see .
[19] => *
[20] => */
[21] =>
[22] => namespace Vvveb\System;
[23] =>
[24] => class Routes {
[25] => const string stringRegex = '{(\w+)}'; // <==
[26] =>
[27] => const string varRegex = '[{#]([a-zA-Z]\w+)({([\d,]+)})?[#}]';
[28] =>
[29] => const string stringLimitRegex = '{([a-zA-Z]\w+){([\d,]+)}}';
[30] =>
[31] => const string numericRegex = '#([a-zA-Z]\w+)#';
[32] =>
[33] => const string numericLimitRegex = '#([a-zA-Z]\w+){([\d,]+)}#';
[34] =>
[35] => const string wildcardRegex = '\*';
[36] =>
[37] => /** @var array */
[38] => private static array $routes = [];
[39] =>
[40] => /** @var array */
[41] => private static array $urls = [];
[42] =>
[43] => /** @var array, count: int}> >|null */
[44] => private static ?array $modules = null;
[45] =>
[46] => private static bool $init = false;
[47] =>
[48] => /**
[49] => * Process a route pattern into regex and store module data.
[50] => *
[51] => * @param string $url The route URL pattern.
[52] => * @param array{module: string, edit?: string} $data Route configuration data.
[53] => * @return string The compiled regex pattern.
[54] => */
[55] => private static function processRoute(string $url, array $data): string {
[56] => $module = $data['module'];
[57] => unset($data['edit'], $data['module']);
[58] =>
[59] => $parameters = [];
[60] =>
[61] => if (preg_match_all('/' . self :: varRegex . '/', $url, $matches)) {
[62] => if ($matches[1]) {
[63] => $parameters = $matches[1];
[64] => }
[65] => }
[66] =>
[67] => if ($data) {
[68] => $parameters = array_merge($parameters, array_keys($data));
[69] => }
[70] =>
[71] => self :: $modules[$module][] = ['url' => $url, 'parameters' => $parameters, 'count' => count($parameters)];
[72] => uasort(self :: $modules[$module], function (array $a, array $b): int {
[73] => return $b['count'] <=> $a['count'];
[74] => });
[75] =>
[76] => $route = $url;
[77] => $url = str_replace('/', '\/', $url);
[78] => $url = preg_replace('/' . self :: numericLimitRegex . '/', '(?<$1>\d{$2})', $url);
[79] => $url = preg_replace('/' . self :: numericRegex . '/', '(?<$1>\d+)', $url);
[80] => $url = preg_replace('/' . self :: stringLimitRegex . '/', '(?<$1>[^$\/]{$2})', $url);
[81] => $url = preg_replace('/' . self :: stringRegex . '/', '(?<$1>[^$\/]+)', $url);
[82] => $url = preg_replace('/' . self :: wildcardRegex . '/', '.*?', $url);
[83] =>
[84] => self :: $urls[$route] = [$url, $module];
[85] =>
[86] => return $url;
[87] => }
[88] =>
[89] => /**
[90] => * Add a route with its URL pattern and configuration data.
[91] => *
[92] => * @param string $url The route URL pattern.
[93] => * @param array{module: string, edit?: string} $data Route configuration data.
[94] => */
[95] => public static function addRoute(string $url, array $data): void {
[96] => self :: $routes[$url] = $data;
[97] => self :: processRoute($url, $data);
[98] => }
[99] =>
[100] => /**
[101] => * Remove one or more routes by URL pattern.
[102] => *
[103] => * @param string|array $url A single URL pattern or array of URL patterns to remove.
[104] => */
[105] => public static function removeRoute(string|array $url): void {
[106] => if (is_array($url)) {
[107] => foreach ($url as $route) {
[108] => $module = self :: $urls[$route] ?? false;
[109] =>
[110] => if ($module) {
[111] => unset(self :: $modules[$module]);
[112] => }
[113] => unset(self :: $urls[$route]);
[114] => }
[115] => } else {
[116] => $module = self :: $urls[$url] ?? false;
[117] =>
[118] => if ($module) {
[119] => unset(self :: $modules[$module]);
[120] => }
[121] => unset(self :: $urls[$url]);
[122] => }
[123] => }
[124] =>
[125] => /**
[126] => * Initialize routes from cache or config files.
[127] => *
[128] => * @param string $app Application name.
[129] => * @param int|null $site_id Optional site ID for site-specific routes.
[130] => * @return bool Always returns true.
[131] => */
[132] => public static function init(string $app = 'app', ?int $site_id = null): bool {
[133] => $cacheDriver = Cache :: getInstance();
[134] => if ($site_id) {
[135] => $cacheKey = $site_id;
[136] => } else {
[137] => $cacheKey = $app;
[138] => }
[139] =>
[140] => if ($result = $cacheDriver->get('routes', $cacheKey)) {
[141] => static::$routes = $result['routes'];
[142] => static::$urls = $result['urls'];
[143] => static::$modules = $result['modules'];
[144] => } else {
[145] => $routesConfig = DIR_ROOT . '/config/';
[146] => if ($site_id) {
[147] => $routesConfig .= "site-$site_id-routes.php";
[148] => } else {
[149] => $routesConfig .= "$app-routes.php";
[150] => }
[151] =>
[152] => if (file_exists($routesConfig)) {
[153] => self :: $routes += include $routesConfig;
[154] => }
[155] => list(self :: $routes) = Event::trigger(__CLASS__, __FUNCTION__ , self :: $routes);
[156] =>
[157] => foreach (self :: $routes as $url => $data) {
[158] => self :: processRoute($url, $data);
[159] => }
[160] =>
[161] => $result = [];
[162] => $result['routes'] = static::$routes;
[163] => $result['modules'] = static::$modules;
[164] => $result['urls'] = static::$urls;
[165] =>
[166] => $cacheDriver->set('routes', $cacheKey, $result);
[167] => }
[168] =>
[169] => self :: $init = true;
[170] =>
[171] => return true;
[172] => }
[173] =>
[174] => /**
[175] => * Match a URL against registered route patterns and return extracted parameters.
[176] => *
[177] => * @param string $url The URL to match.
[178] => * @return array{route: string, module: string, pattern: string, [string]: string}|false Matched parameters or false.
[179] => */
[180] => public static function match(string $url): array|false {
[181] => if (! self :: $init) {
[182] => self :: init();
[183] => }
[184] => $url = preg_replace('/\?.*$/', '', str_replace('//', '/', $url));
[185] =>
[186] => foreach (self :: $urls as $route => $data) {
[187] => $params = static::$routes[$route] ?? '';
[188] => list($pattern, $module) = $data;
[189] =>
[190] => if ($url == $pattern || preg_match('/^' . $pattern . '$/', $url, $matches)) {
[191] => $parameters = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
[192] =>
[193] => $parameters['route'] = $route;
[194] => $parameters['module'] = $module;
[195] => $parameters['pattern'] = $pattern;
[196] =>
[197] => $parameters += $params;
[198] =>
[199] => return $parameters;
[200] => }
[201] => }
[202] =>
[203] => return false;
[204] => }
[205] =>
[206] => /**
[207] => * Get the configuration data for a route by its pattern key.
[208] => *
[209] => * @param string $route The route pattern key.
[210] => * @return array{module: string, edit?: string} Route data or empty array.
[211] => */
[212] => public static function get(string $route): array {
[213] => return self :: $routes[$route] ?? [];
[214] => }
[215] =>
[216] => /**
[217] => * Get all registered routes.
[218] => *
[219] => * @return array All routes.
[220] => */
[221] => public static function getRoutes(): array {
[222] => return self :: $routes ?? [];
[223] => }
[224] =>
[225] => /**
[226] => * Replace variable placeholders in a URL with parameter values.
[227] => *
[228] => * @param string $url URL pattern with placeholders.
[229] => * @param array $parameters Key-value pairs for replacement.
[230] => * @return string The URL with placeholders replaced.
[231] => */
[232] => public static function varReplace(string $url, array $parameters): string {
[233] => return preg_replace_callback('/' . self :: stringRegex . '|' . self :: numericRegex . '/',
[234] => function (array $matches) use ($parameters): string {
[235] => $var = $matches[1];
[236] =>
[237] => if (isset($parameters[$var])) {
[238] => return $parameters[$var];
[239] => }
[240] =>
[241] => return '';
[242] => }, $url);
[243] => }
[244] =>
[245] => /**
[246] => * Get route data for a module name.
[247] => *
[248] => * @param string $module The module name.
[249] => * @return array, count: int}> Route data for the module.
[250] => */
[251] => public static function getRouteData(string $module): array {
[252] => if (! self :: $init) {
[253] => self :: init();
[254] => }
[255] =>
[256] => return self :: $modules[$module] ?? [];
[257] => }
[258] =>
[259] => /**
[260] => * Get URL data by matching against registered routes.
[261] => *
[262] => * @param string|false $url The URL to resolve, or false to use current URL.
[263] => * @return array|false Matched route parameters with route metadata, or false on no match.
[264] => */
[265] => public static function getUrlData(string|false $url = false): array|false {
[266] => if (! $url) {
[267] => $url = \Vvveb\getCurrentUrl();
[268] => }
[269] =>
[270] => $parameters = self :: match($url);
[271] => $route = stripslashes($parameters['route'] ?? '');
[272] =>
[273] => if ($parameters) {
[274] => $parameters = $parameters + self :: $routes[$route];
[275] =>
[276] => if (isset($parameters['edit'])) {
[277] => $parameters['edit'] = self :: varReplace($parameters['edit'], $parameters);
[278] => }
[279] => }
[280] =>
[281] => return $parameters;
[282] => }
[283] =>
[284] => /**
[285] => * Generate a URL from a module route name and parameters.
[286] => *
[287] => * @param string $route The module/route name.
[288] => * @param array|false $parameters Query parameters or false for no parameters.
[289] => * @return string|null The resolved URL, or null if the route is not found.
[290] => */
[291] => public static function url(string $route, array|false $parameters = false): ?string {
[292] => if (! self :: $init) {
[293] => self :: init();
[294] => }
[295] =>
[296] => if (isset(self :: $modules[$route])) {
[297] => $pattern = self :: $modules[$route][0]['url'] ?? '';
[298] =>
[299] => if ($parameters && isset($parameters['route'])) {
[300] => unset($parameters['route']);
[301] => }
[302] =>
[303] => $parameters_count = is_array($parameters) ? count($parameters) : 0;
[304] => $param_keys = is_array($parameters) ? array_keys($parameters) : [];
[305] =>
[306] => foreach (self :: $modules[$route] as $value) {
[307] => if ($value['parameters'] && $parameters_count) {
[308] => if (count(array_intersect($value['parameters'], $param_keys)) === count($value['parameters'])) {
[309] => $pattern = $value['url'];
[310] =>
[311] => break;
[312] => }
[313] => } else {
[314] => $no_parameters = $value['url'];
[315] => }
[316] => }
[317] =>
[318] => if (! $parameters) {
[319] => $pattern = $no_parameters;
[320] => }
[321] =>
[322] => $missing = false;
[323] => $url = preg_replace_callback('/' . self :: varRegex . '/',
[324] => function (array $matches) use ($parameters, &$missing): string {
[325] => $var = $matches[1];
[326] =>
[327] => if (isset($parameters[$var])) {
[328] => return $parameters[$var];
[329] => } else {
[330] => $missing = true;
[331] => }
[332] =>
[333] => return '';
[334] => }, $pattern);
[335] =>
[336] => if ($missing) {
[337] => return '/?route=' . $route . '&' . (is_array($parameters) ? http_build_query($parameters) : '');
[338] => } else {
[339] => return $url;
[340] => }
[341] => }
[342] =>
[343] => return null;
[344] => }
[345] => }
)
)