LinkHandler now supports routing
authorAlexander Ebert <ebert@woltlab.com>
Wed, 12 Oct 2011 11:46:34 +0000 (13:46 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 12 Oct 2011 11:46:34 +0000 (13:46 +0200)
wcfsetup/install/files/lib/system/request/LinkHandler.class.php
wcfsetup/install/files/lib/system/request/Route.class.php
wcfsetup/install/files/lib/system/request/RouteHandler.class.php
wcfsetup/install/files/lib/system/template/plugin/LinkBlockTemplatePlugin.class.php

index 02b927c388a968c0b79f125e4bb71a9d14eccd9f..09ccf76bd6ba8b018537177ff896eb6757225080 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 namespace wcf\system\request;
 use wcf\system\application\ApplicationHandler;
+use wcf\system\request\RouteHandler;
 use wcf\system\SingletonFactory;
 
 /**
@@ -18,28 +19,50 @@ class LinkHandler extends 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;
        }
 }
index 62fb7d5c5bff9d5005605ff8f442e5253e81517e..561d7661e528ed210d48ebce89e2195099846127 100644 (file)
@@ -180,6 +180,61 @@ class Route {
                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.
         * 
index bb0146e6c24d294c9b296080db8a8d9253725060..0d23509144c6fb9c88299cdd8d62643461c9638d 100644 (file)
@@ -16,6 +16,12 @@ use wcf\system\SingletonFactory;
  * @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>
@@ -70,10 +76,12 @@ class RouteHandler extends SingletonFactory {
         * @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;
                        }
                        
@@ -105,4 +113,25 @@ class RouteHandler extends SingletonFactory {
                        $_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.");
+       }
 }
index 093dcee09863e3ba696ea455bc2f9fb113a764ef..2c2fcefb9342138bd6aa4dac2656fc19389f67be 100644 (file)
@@ -27,12 +27,11 @@ class LinkBlockTemplatePlugin implements IBlockTemplatePlugin {
         * @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);
        }
        
        /**