/** * Application entry point. */ public static function start() { // hide errors error_reporting(E_ALL); ini_set('display_errors', 0); // use UTC on server date_default_timezone_set('UTC'); // error/exception Handlers set_error_handler([__CLASS__, 'error']); set_exception_handler([__CLASS__, 'exception']); register_shutdown_function([__CLASS__, 'shutdown']); // configuration define('BRAMBLE_URL', self::get_app_url()); Stopwatch::start()->register(); Log::time('~init'); // handle request Request::execute(); }
/** * @param bool $rebuild * @return RouteMap */ public static function instance($rebuild = false) { return Cache::load('routes', function () { $lookup = []; // todo: add support for optional centralized routes foreach (Directory::search(BRAMBLE_DIR . '/Controllers', Directory::R_PHP, [Directory::R_HIDDEN]) as $file) { $controller_name = sprintf('%s\\%s', BRAMBLE_NS, substr(substr($file, strlen(BRAMBLE_DIR) + 1), 0, -4)); $reflection_class = new \ReflectionClass($controller_name); if (!$reflection_class->isAbstract()) { $controller = new $controller_name(Request::get()); if (!$controller instanceof Controller) { throw new \Exception('Only controllers are allowed in this directory'); } foreach ($controller->routes() as $route) { $route->defaults(['controller' => $controller_name]); $route->compile($lookup); } } } return new self($lookup); }, $rebuild); }
public function compile(array &$lookup) { // escape necessary characters other than :()<> $regex = preg_replace('`' . self::REGEX_ESCAPE . '`', '\\\\$0', $this->m_uri); // mark parentheses as non-capturing and optional if (strpos($regex, '(') !== false) { $regex = str_replace('(', '(?:', $regex); $regex = str_replace(')', ')?', $regex); } // match keys and replace with appropriate regexes if (preg_match_all(sprintf('/<(?<name>%s)>/', self::REGEX_KEY_NAME), $regex, $matches, PREG_SET_ORDER)) { foreach ($matches as $set) { $name = $set['name']; $key_regex = self::R_ANYTHING; if (isset($this->m_regexes[$name])) { $key_regex = $this->m_regexes[$name]; if ($key_regex === self::R_LITERAL) { $key_regex = $name; } } $regex = str_replace($set[0], "(?<{$name}>{$key_regex})", $regex); } } // start with the lookup root $current =& $lookup; // find the starting literal components $position = strspn($this->m_uri ^ $regex, ""); $similar = substr($this->m_uri, 0, $position); if (substr($similar, -1) === '(') { $similar = substr($similar, 0, -1); } if ($similar) { // add parts to the common lookup $similar_parts = array_filter(explode('/', $similar)); foreach ($similar_parts as $part) { if (!isset($current[$part])) { $current[$part] = []; } $current =& $current[$part]; } } // wrap with safe delimiter $delimiter = '`'; if (strpos($regex, $delimiter)) { $delimiter = ""; } $regex = sprintf('%s^%s$%s', $delimiter, $regex, $delimiter); // build method mask $methods = 0; if ($this->m_methods) { foreach ($this->m_methods as $method) { $methods |= Request::method_flag($method); } } $compiled = new CompiledRoute($regex, $this->m_params, $this->m_actions, $methods, $this->m_method); // add compiled route to lookup $current[] = $compiled; return $compiled; }