/** * Calls public method if exists. * @param string * @param array * @return bool does method exist? */ protected function tryCall($method, array $params) { $class = $this->getClass(); if (PresenterHelpers::isMethodCallable($class, $method)) { $args = PresenterHelpers::paramsToArgs($class, $method, $params); call_user_func_array(array($this, $method), $args); return TRUE; } return FALSE; }
/** * PresenterRequest/URL factory. * @param PresenterComponent base * @param string destination in format "[[module:]presenter:]action" or "signal!" * @param array array of arguments * @param string forward|redirect|link * @return string URL * @throws InvalidLinkException * @internal */ protected final function createRequest($component, $destination, array $args, $mode) { // note: createRequest supposes that saveState(), run() & tryCall() behaviour is final // cached services for better performance static $presenterLoader, $router, $httpRequest; if ($presenterLoader === NULL) { $presenterLoader = $this->getApplication()->getPresenterLoader(); $router = $this->getApplication()->getRouter(); $httpRequest = $this->getHttpRequest(); } $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); // requires disabled magic quotes $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 Presenter || substr($destination, -1) === '!') { $signal = rtrim($destination, '!'); if ($signal == NULL) { // intentionally == 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; $a = strrpos($destination, ':'); if ($a === FALSE) { $action = $destination === 'this' ? $this->action : $destination; $presenter = $this->getName(); $presenterClass = $this->getClass(); } else { $action = (string) substr($destination, $a + 1); if ($destination[0] === ':') { // absolute if ($a < 2) { throw new InvalidLinkException("Missing presenter name in '{$destination}'."); } $presenter = substr($destination, 1, $a - 1); } else { // relative $presenter = $this->getName(); $b = strrpos($presenter, ':'); if ($b === FALSE) { // no module $presenter = substr($destination, 0, $a); } else { // with module $presenter = substr($presenter, 0, $b + 1) . substr($destination, 0, $a); } } $presenterClass = $presenterLoader->getPresenterClass($presenter); } // PROCESS SIGNAL ARGUMENTS if (isset($signal)) { // $component must be IStatePersistent $class = get_class($component); if ($signal === 'this') { // means "no signal" $signal = ''; if (array_key_exists(0, $args)) { throw new InvalidLinkException("Extra parameter for signal '{$class}:{$signal}!'."); } } elseif (strpos($signal, self::NAME_SEPARATOR) === FALSE) { // TODO: AppForm exception // counterpart of signalReceived() & tryCall() $method = $component->formatSignalMethod($signal); if (!PresenterHelpers::isMethodCallable($class, $method)) { throw new InvalidLinkException("Unknown signal '{$class}:{$signal}!'."); } if ($args) { // convert indexed parameters to named PresenterHelpers::argsToParams($class, $method, $args); } } // counterpart of IStatePersistent if ($args && array_intersect_key($args, PresenterHelpers::getPersistentParams($class))) { $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 = $presenterClass::$defaultAction;*/ // in PHP 5.3 $action = self::$defaultAction; } $current = ($action === '*' || $action === $this->action) && $presenterClass === $this->getClass(); // TODO if ($args || $destination === 'this') { // counterpart of run() & tryCall() // in PHP 5.3 $method = call_user_func(array($presenterClass, 'formatActionMethod'), $action); if (!PresenterHelpers::isMethodCallable($presenterClass, $method)) { $method = 'present' . $action; if (!PresenterHelpers::isMethodCallable($presenterClass, $method)) { // back compatibility // in PHP 5.3 $method = call_user_func(array($presenterClass, 'formatRenderMethod'), $action); if (!PresenterHelpers::isMethodCallable($presenterClass, $method)) { $method = NULL; } } } // convert indexed parameters to named if ($method === NULL) { if (array_key_exists(0, $args)) { throw new InvalidLinkException("Extra parameter for '{$presenter}:{$action}'."); } } elseif ($destination === 'this') { PresenterHelpers::argsToParams($presenterClass, $method, $args, $this->params); } else { PresenterHelpers::argsToParams($presenterClass, $method, $args); } } // counterpart of IStatePersistent if ($args && array_intersect_key($args, PresenterHelpers::getPersistentParams($presenterClass))) { $this->saveState($args, $presenterClass); } $globalState = $this->getGlobalState($destination === 'this' ? NULL : $presenterClass); if ($current && $args) { $tmp = $globalState + $this->params; foreach ($args as $key => $val) { if ((string) $val !== (isset($tmp[$key]) ? (string) $tmp[$key] : '')) { $current = FALSE; break; } } } $args += $globalState; } // ADD ACTION & SIGNAL & FLASH $args[self::ACTION_KEY] = $action; if (!empty($signal)) { $args[self::SIGNAL_KEY] = $component->getParamId($signal); $current = $current && $args[self::SIGNAL_KEY] === $this->getParam(self::SIGNAL_KEY); } if ($mode === 'redirect' && $this->hasFlashSession()) { $args[self::FLASH_KEY] = $this->getParam(self::FLASH_KEY); } $this->lastCreatedRequest = new PresenterRequest($presenter, PresenterRequest::FORWARD, $args, array(), array()); $this->lastCreatedRequestFlag = array('current' => $current); if ($mode === 'forward') { return; } // CONSTRUCT URL $uri = $router->constructUrl($this->lastCreatedRequest, $httpRequest); if ($uri === 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) { $hostUri = $httpRequest->getUri()->hostUri; if (strncmp($uri, $hostUri, strlen($hostUri)) === 0) { $uri = substr($uri, strlen($hostUri)); } } return $uri . $fragment; }