Example #1
0
 /**
  * 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;
 }