/** * @param string URL mask, e.g. '<presenter>/<action>/<id \d{1,3}>' * @param array|string|\Closure default values or metadata or callback for NetteModule\MicroPresenter * @param int flags */ public function __construct($mask, $metadata = [], $flags = 0) { if (is_string($metadata)) { list($presenter, $action) = Nette\Application\Helpers::splitName($metadata); if (!$presenter) { throw new Nette\InvalidArgumentException("Second argument must be array or string in format Presenter:action, '{$metadata}' given."); } $metadata = [self::PRESENTER_KEY => $presenter]; if ($action !== '') { $metadata['action'] = $action; } } elseif ($metadata instanceof \Closure || $metadata instanceof Nette\Callback) { if ($metadata instanceof Nette\Callback) { trigger_error('Nette\\Callback is deprecated, use Nette\\Utils\\Callback::closure().', E_USER_DEPRECATED); } $metadata = [self::PRESENTER_KEY => 'Nette:Micro', 'callback' => $metadata]; } $this->flags = $flags | static::$defaultFlags; $this->setMask($mask, $metadata); if (static::$defaultFlags) { trigger_error('Route::$defaultFlags is deprecated, router by default keeps the used protocol.', E_USER_DEPRECATED); } elseif ($flags & self::SECURED) { trigger_error('Router::SECURED is deprecated, specify scheme in mask.', E_USER_DEPRECATED); $this->scheme = 'https'; } }
public function run(Nette\Application\Request $request) { $exception = $request->getParameter('exception'); if ($exception instanceof Nette\Application\BadRequestException) { list($module, , $sep) = Nette\Application\Helpers::splitName($request->getPresenterName()); return new Responses\ForwardResponse($request->setPresenterName($module . $sep . 'Error4xx')); } $this->logger->log($exception, ILogger::EXCEPTION); return new Responses\CallbackResponse(function () { require __DIR__ . '/templates/Error/500.phtml'; }); }
/** * @return Nette\Application\IResponse */ public function run(Nette\Application\Request $request) { $e = $request->getParameter('exception'); if ($e instanceof Nette\Application\BadRequestException) { // $this->logger->log("HTTP code {$e->getCode()}: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", 'access'); list($module, , $sep) = Nette\Application\Helpers::splitName($request->getPresenterName()); return new Responses\ForwardResponse($request->setPresenterName($module . $sep . 'Error4xx')); } $this->logger->log($e, ILogger::EXCEPTION); return new Responses\CallbackResponse(function () { require __DIR__ . '/templates/Error/500.phtml'; }); }
/** * Maps command line arguments to a Request object. * @return Nette\Application\Request|NULL */ public function match(Nette\Http\IRequest $httpRequest) { if (empty($_SERVER['argv']) || !is_array($_SERVER['argv'])) { return NULL; } $names = [self::PRESENTER_KEY]; $params = $this->defaults; $args = $_SERVER['argv']; array_shift($args); $args[] = '--'; foreach ($args as $arg) { $opt = preg_replace('#/|-+#A', '', $arg); if ($opt === $arg) { if (isset($flag) || ($flag = array_shift($names))) { $params[$flag] = $arg; } else { $params[] = $arg; } $flag = NULL; continue; } if (isset($flag)) { $params[$flag] = TRUE; $flag = NULL; } if ($opt !== '') { $pair = explode('=', $opt, 2); if (isset($pair[1])) { $params[$pair[0]] = $pair[1]; } else { $flag = $pair[0]; } } } if (!isset($params[self::PRESENTER_KEY])) { throw new Nette\InvalidStateException('Missing presenter & action in route definition.'); } list($module, $presenter) = Nette\Application\Helpers::splitName($params[self::PRESENTER_KEY]); if ($module !== '') { $params[self::PRESENTER_KEY] = $presenter; $presenter = $module; } return new Application\Request($presenter, 'CLI', $params); }
/** * @param array default values * @param int flags */ public function __construct($defaults = [], $flags = 0) { if (is_string($defaults)) { list($presenter, $action) = Nette\Application\Helpers::splitName($defaults); if (!$presenter) { throw new Nette\InvalidArgumentException("Argument must be array or string in format Presenter:action, '{$defaults}' given."); } $defaults = [self::PRESENTER_KEY => $presenter, 'action' => $action === '' ? Application\UI\Presenter::DEFAULT_ACTION : $action]; } if (isset($defaults[self::MODULE_KEY])) { $this->module = $defaults[self::MODULE_KEY] . ':'; unset($defaults[self::MODULE_KEY]); } $this->defaults = $defaults; $this->flags = $flags; if ($flags & self::SECURED) { trigger_error('IRouter::SECURED is deprecated, router by default keeps the used protocol.', E_USER_DEPRECATED); } }
/** * Formats view template file names. * @return array */ public function formatTemplateFiles() { list(, $presenter) = \Nette\Application\Helpers::splitName($this->getName()); $dir = dirname($this->getReflection()->getFileName()); $dir = is_dir("{$dir}/Templates") ? $dir : dirname($dir); return ["{$dir}/Templates/{$presenter}/{$this->view}.latte"]; }
/** * Request/URL factory. * @param Component base * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]" * @param array array of arguments * @param string forward|redirect|link * @return string URL * @throws InvalidLinkException * @internal */ protected function createRequest($component, $destination, array $args, $mode) { // note: createRequest supposes that saveState(), run() & tryCall() behaviour is final $this->lastCreatedRequest = $this->lastCreatedRequestFlag = NULL; // PARSE DESTINATION // 1) fragment $a = strpos($destination, '#'); if ($a === FALSE) { $fragment = ''; } else { $fragment = substr($destination, $a); $destination = substr($destination, 0, $a); } // 2) ?query syntax $a = strpos($destination, '?'); if ($a !== FALSE) { parse_str(substr($destination, $a + 1), $args); $destination = substr($destination, 0, $a); } // 3) URL scheme $a = strpos($destination, '//'); if ($a === FALSE) { $scheme = FALSE; } else { $scheme = substr($destination, 0, $a); $destination = substr($destination, $a + 2); } // 4) signal or empty if (!$component instanceof self || substr($destination, -1) === '!') { list($cname, $signal) = Helpers::splitName(rtrim($destination, '!')); if ($cname !== '') { $component = $component->getComponent(strtr($cname, ':', '-')); } if ($signal === '') { throw new InvalidLinkException('Signal must be non-empty string.'); } $destination = 'this'; } if ($destination == NULL) { // intentionally == throw new InvalidLinkException('Destination must be non-empty string.'); } // 5) presenter: action $current = FALSE; list($presenter, $action) = Helpers::splitName($destination); if ($presenter === '') { $action = $destination === 'this' ? $this->action : $action; $presenter = $this->getName(); $presenterClass = get_class($this); } else { if ($presenter[0] === ':') { // absolute $presenter = substr($presenter, 1); if (!$presenter) { throw new InvalidLinkException("Missing presenter name in '{$destination}'."); } } else { // relative list($module, , $sep) = Helpers::splitName($this->getName()); $presenter = $module . $sep . $presenter; } if (!$this->presenterFactory) { throw new Nette\InvalidStateException('Unable to create link to other presenter, service PresenterFactory has not been set.'); } try { $presenterClass = $this->presenterFactory->getPresenterClass($presenter); } catch (Application\InvalidPresenterException $e) { throw new InvalidLinkException($e->getMessage(), NULL, $e); } } // PROCESS SIGNAL ARGUMENTS if (isset($signal)) { // $component must be IStatePersistent $reflection = new ComponentReflection(get_class($component)); if ($signal === 'this') { // means "no signal" $signal = ''; if (array_key_exists(0, $args)) { throw new InvalidLinkException("Unable to pass parameters to 'this!' signal."); } } elseif (strpos($signal, self::NAME_SEPARATOR) === FALSE) { // counterpart of signalReceived() & tryCall() $method = $component->formatSignalMethod($signal); if (!$reflection->hasCallableMethod($method)) { throw new InvalidLinkException("Unknown signal '{$signal}', missing handler {$reflection->getName()}::{$method}()"); } // convert indexed parameters to named self::argsToParams(get_class($component), $method, $args, [], $missing); } // counterpart of IStatePersistent if ($args && array_intersect_key($args, $reflection->getPersistentParams())) { $component->saveState($args); } if ($args && $component !== $this) { $prefix = $component->getUniqueId() . self::NAME_SEPARATOR; foreach ($args as $key => $val) { unset($args[$key]); $args[$prefix . $key] = $val; } } } // PROCESS ARGUMENTS if (is_subclass_of($presenterClass, __CLASS__)) { if ($action === '') { $action = self::DEFAULT_ACTION; } $current = ($action === '*' || strcasecmp($action, $this->action) === 0) && $presenterClass === get_class($this); $reflection = new ComponentReflection($presenterClass); // counterpart of run() & tryCall() $method = $presenterClass::formatActionMethod($action); if (!$reflection->hasCallableMethod($method)) { $method = $presenterClass::formatRenderMethod($action); if (!$reflection->hasCallableMethod($method)) { $method = NULL; } } // convert indexed parameters to named if ($method === NULL) { if (array_key_exists(0, $args)) { throw new InvalidLinkException("Unable to pass parameters to action '{$presenter}:{$action}', missing corresponding method."); } } else { self::argsToParams($presenterClass, $method, $args, $destination === 'this' ? $this->params : [], $missing); } // counterpart of IStatePersistent if ($args && array_intersect_key($args, $reflection->getPersistentParams())) { $this->saveState($args, $reflection); } if ($mode === 'redirect') { $this->saveGlobalState(); } $globalState = $this->getGlobalState($destination === 'this' ? NULL : $presenterClass); if ($current && $args) { $tmp = $globalState + $this->params; foreach ($args as $key => $val) { if (http_build_query([$val]) !== (isset($tmp[$key]) ? http_build_query([$tmp[$key]]) : '')) { $current = FALSE; break; } } } $args += $globalState; } if ($mode !== 'test' && !empty($missing)) { foreach ($missing as $rp) { if (!array_key_exists($rp->getName(), $args)) { throw new InvalidLinkException("Missing parameter \${$rp->getName()} required by {$rp->getDeclaringClass()->getName()}::{$rp->getDeclaringFunction()->getName()}()"); } } } // ADD ACTION & SIGNAL & FLASH if ($action) { $args[self::ACTION_KEY] = $action; } if (!empty($signal)) { $args[self::SIGNAL_KEY] = $component->getParameterId($signal); $current = $current && $args[self::SIGNAL_KEY] === $this->getParameter(self::SIGNAL_KEY); } if (($mode === 'redirect' || $mode === 'forward') && $this->hasFlashSession()) { $args[self::FLASH_KEY] = $this->getFlashKey(); } $this->lastCreatedRequest = new Application\Request($presenter, Application\Request::FORWARD, $args, [], []); $this->lastCreatedRequestFlag = ['current' => $current]; if ($mode === 'forward' || $mode === 'test') { return; } // CONSTRUCT URL if ($this->refUrlCache === NULL) { $this->refUrlCache = new Http\Url($this->httpRequest->getUrl()); $this->refUrlCache->setPath($this->httpRequest->getUrl()->getScriptPath()); } if (!$this->router) { throw new Nette\InvalidStateException('Unable to generate URL, service Router has not been set.'); } $url = $this->router->constructUrl($this->lastCreatedRequest, $this->refUrlCache); if ($url === NULL) { unset($args[self::ACTION_KEY]); $params = urldecode(http_build_query($args, NULL, ', ')); throw new InvalidLinkException("No route for {$presenter}:{$action}({$params})"); } // make URL relative if possible if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls) { $hostUrl = $this->refUrlCache->getHostUrl() . '/'; if (strncmp($url, $hostUrl, strlen($hostUrl)) === 0) { $url = substr($url, strlen($hostUrl) - 1); } } return $url . $fragment; }