'application/Espo/Resources/routes.json', 'modulePath' => 'application/Espo/Modules/{*}/Resources/routes.json', 'customPath' => 'custom/Espo/Custom/Resources/routes.json', ]; private $config; private $metadata; private $fileManager; private $dataCache; public function __construct(Config $config, Metadata $metadata, FileManager $fileManager, DataCache $dataCache) { $this->config = $config; $this->metadata = $metadata; $this->fileManager = $fileManager; $this->dataCache = $dataCache; } /** * Get all routes. */ public function getFullList() : array { if (!isset($this->data)) { $this->init(); } return $this->data; } protected function init() { $useCache = $this->config->get('useCache'); if ($this->dataCache->has($this->cacheKey) && $useCache) { $this->data = $this->dataCache->get($this->cacheKey); return; } $this->data = $this->unify(); if ($useCache) { $this->dataCache->store($this->cacheKey, $this->data); } } protected function unify() : array { $data = $this->addDataFromFile([], $this->paths['customPath']); $moduleData = []; foreach ($this->metadata->getModuleList() as $moduleName) { $modulePath = str_replace('{*}', $moduleName, $this->paths['modulePath']); foreach ($this->addDataFromFile([], $modulePath) as $row) { $key = $row['method'] . $row['route']; $moduleData[$key] = $row; } } $data = array_merge($data, array_values($moduleData)); $data = $this->addDataFromFile($data, $this->paths['corePath']); return $data; } protected function addDataFromFile(array $currentData, string $routeFile) : array { if (!file_exists($routeFile)) { return $currentData; } $content = $this->fileManager->getContents($routeFile); $data = Json::getArrayData($content); if (empty($data)) { $GLOBALS['log']->warning("Route: No data or syntax error in '{$routeFile}'."); return $currentData; } return $this->appendRoutesToData($currentData, $data); } protected function appendRoutesToData(array $data, array $newData) : array { foreach ($newData as $route) { $route['route'] = $this->adjustPath($route['route']); if (isset($route['conditions'])) { $route['noAuth'] = !($route['conditions']['auth'] ?? true); unset($route['conditions']); } if (self::isRouteInList($route, $data)) { continue; } $data[] = $route; } return $data; } /** * Check and adjust the route path. */ protected function adjustPath(string $routePath) : string { $routePath = trim($routePath); // to fast route format $routePath = preg_replace('/\:([a-zA-Z0-9]+)/', '{${1}}', $routePath); if (substr($routePath, 0, 1) !== '/') { return '/' . $routePath; } return $routePath; } public static function detectBasePath() : string { $scriptName = parse_url($_SERVER['SCRIPT_NAME'] , PHP_URL_PATH); $scriptDir = dirname($scriptName); $uri = parse_url('http://any.com' . $_SERVER['REQUEST_URI'], PHP_URL_PATH); if (stripos($uri, $scriptName) === 0) { return $scriptName; } if ($scriptDir !== '/' && stripos($uri, $scriptDir) === 0) { return $scriptDir; } return ''; } public static function detectEntryPointRoute() : string { $basePath = self::detectBasePath(); $uri = parse_url('http://any.com' . $_SERVER['REQUEST_URI'], PHP_URL_PATH); if ($uri === $basePath) { return '/'; } if (stripos($uri, $basePath) === 0) { return substr($uri, strlen($basePath)); } return '/'; } static protected function isRouteInList(array $newRoute, array $routeList) : bool { foreach ($routeList as $route) { if (Util::isEquals($route, $newRoute)) { return true; } } return false; } }