<?php
namespace wcf\system\request;
use wcf\system\application\ApplicationHandler;
+use wcf\system\request\RouteHandler;
use wcf\system\SingletonFactory;
/**
* Returns a relative link.
*
* @param string $url
- * @param string $abbreviation
+ * @param array $parameters
* @return string
*/
- public function getLink($url, $abbreviation = 'wcf') {
- $applicationGroup = ApplicationHandler::getInstance()->getActiveGroup();
-
- // not within an application group, return unmodified url
- if ($applicationGroup === null) {
- return $url . (strstr($url, '?') === false ? SID_ARG_1ST : SID_ARG_2ND_NOT_ENCODED);
+ public function getLink($url, array $parameters = array()) {
+ $abbreviation = 'wcf';
+ $isRaw = false;
+ if (isset($parameters['application'])) {
+ $abbreviation = $parameters['application'];
+ unset($parameters['application']);
+ }
+ if (isset($parameters['isRaw'])) {
+ $isRaw = $parameters['isRaw'];
+ unset($parameters['isRaw']);
}
- // try to resolve abbreviation
- $application = null;
- if ($abbreviation != 'wcf') {
- $application = ApplicationHandler::getInstance()->getApplication($abbreviation);
+ // build route
+ if (isset($parameters['controller'])) {
+ $routeURL = RouteHandler::getInstance()->buildRoute($parameters);
+ if (!$isRaw) {
+ $routeURL .= (strpos($routeURL, '?') === false) ? '?' : '&';
+ }
+ $url = $routeURL . $url;
}
- // fallback to primary application if abbreviation is 'wcf' or unknown
- if ($application === null) {
- $application = ApplicationHandler::getInstance()->getPrimaryApplication();
+ // append session id
+ $url .= (strpos($url, '?') === false) ? SID_ARG_1ST : SID_ARG_2ND_NOT_ENCODED;
+
+ // handle application groups
+ $applicationGroup = ApplicationHandler::getInstance()->getActiveGroup();
+ if ($applicationGroup !== null) {
+ // try to resolve abbreviation
+ $application = null;
+ if ($abbreviation != 'wcf') {
+ $application = ApplicationHandler::getInstance()->getApplication($abbreviation);
+ }
+
+ // fallback to primary application if abbreviation is 'wcf' or unknown
+ if ($application === null) {
+ $application = ApplicationHandler::getInstance()->getPrimaryApplication();
+ }
+
+ $url = $application->domainName . $application->domainPath . $url;
}
- return $application->domainName . $application->domainPath . $url . (strstr($url, '?') === false ? SID_ARG_1ST : SID_ARG_2ND_NOT_ENCODED);
+ return $url;
}
}
return array_values($urlParts);
}
+ /**
+ * Returns true if current route can handle the build request.
+ *
+ * @param array $components
+ * @return boolean
+ */
+ public function canHandle(array $components) {
+ foreach ($this->routeSchema as $schemaPart) {
+ if (isset($components[$schemaPart])) {
+ // validate parameter against a regex pattern
+ if ($this->parameterOptions[$schemaPart]['regexPattern'] !== null) {
+ $pattern = '~^' . $this->parameterOptions[$schemaPart]['regexPattern'] . '$~';
+ if (!preg_match($pattern, $components[$schemaPart])) {
+ return false;
+ }
+ }
+ }
+ else {
+ if (isset($this->parameterOptions[$schemaPart])) {
+ // default value is provided
+ if ($this->parameterOptions[$schemaPart]['default'] !== null) {
+ continue;
+ }
+
+ // required parameter is missing
+ if (!$this->parameterOptions[$schemaPart]['isOptional']) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Builds a link upon route components.
+ *
+ * @param array $components
+ * @return string
+ */
+ public function buildLink(array $components) {
+ $link = 'index.php/';
+ foreach ($this->routeSchema as $component) {
+ $link .= $components[$component] . '/';
+ unset($components[$component]);
+ }
+
+ if (!empty($components)) {
+ $link .= '?' . html_build_query($components, '', '&');
+ }
+
+ return $link;
+ }
+
/**
* Returns true if route applies for ACP.
*
* @category Community Framework
*/
class RouteHandler extends SingletonFactory {
+ /**
+ * router filter for ACP
+ * @var boolean
+ */
+ protected $isACP = false;
+
/**
* list of available routes
* @var array<wcf\system\request\Route>
* @return boolean
*/
public function matches($isACP) {
+ $this->isACP = $isACP;
+
$pathInfo = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : '';
foreach ($this->routes as $route) {
- if ($isACP != $route->isACP()) {
+ if ($this->isACP != $route->isACP()) {
continue;
}
$_REQUEST[$key] = $value;
}
}
+
+ /**
+ * Builds a route based upon route components, this is nothing
+ * but a reverse lookup.
+ *
+ * @param array $components
+ * @return string
+ */
+ public function buildRoute(array $components) {
+ foreach ($this->routes as $route) {
+ if ($this->isACP != $route->isACP()) {
+ continue;
+ }
+
+ if ($route->canHandle($components)) {
+ return $route->buildLink($components);
+ }
+ }
+
+ throw new SystemException("Unable to build route, no available route is satisfied.");
+ }
}
* @see wcf\system\template\IBlockTemplatePlugin::execute()
*/
public function execute($tagArgs, $blockContent, TemplateEngine $tplObj) {
- $application = 'wcf';
- if (!empty($tagArgs['application'])) {
- $application = $tagArgs['application'];
+ if (!isset($tagArgs['application']) || empty($tagArgs['application'])) {
+ $tagArgs['application'] = 'wcf';
}
- return LinkHandler::getInstance()->getLink($blockContent, $application);
+ return LinkHandler::getInstance()->getLink($blockContent, $tagArgs);
}
/**