diff --git a/libraries/cms/application/cms.php b/libraries/cms/application/cms.php index ba60e1970e5ac..55d9ec2d455f9 100644 --- a/libraries/cms/application/cms.php +++ b/libraries/cms/application/cms.php @@ -1057,7 +1057,7 @@ protected function route() $uri = clone JUri::getInstance(); $router = static::getRouter(); - $result = $router->parse($uri); + $result = $router->parse($uri, true); foreach ($result as $key => $value) { diff --git a/libraries/cms/application/site.php b/libraries/cms/application/site.php index 5d325a79a6ed1..d45948548b8e6 100644 --- a/libraries/cms/application/site.php +++ b/libraries/cms/application/site.php @@ -156,7 +156,7 @@ public function dispatch($component = null) $document->setMetaData('rights', $this->get('MetaRights')); - if ($router->getMode() == JROUTER_MODE_SEF) + if ($this->get('sef')) { $document->setBase(htmlspecialchars(JUri::current())); } diff --git a/libraries/cms/router/administrator.php b/libraries/cms/router/administrator.php index aa7a5b4e7dcdf..161193906e7e9 100644 --- a/libraries/cms/router/administrator.php +++ b/libraries/cms/router/administrator.php @@ -19,13 +19,15 @@ class JRouterAdministrator extends JRouter /** * Function to convert a route to an internal URI. * - * @param JUri &$uri The uri. + * @param JUri &$uri The uri. + * @param bool $setVars Set the parsed data in the internal + * storage for current-request-URLs * * @return array * * @since 1.5 */ - public function parse(&$uri) + public function parse(&$uri, $setVars = false) { return array(); } diff --git a/libraries/cms/router/router.php b/libraries/cms/router/router.php index 6b9bbdfb3e14a..0aadfe153827e 100644 --- a/libraries/cms/router/router.php +++ b/libraries/cms/router/router.php @@ -9,20 +9,6 @@ defined('JPATH_PLATFORM') or die; -/** - * Mask for the raw routing mode - * - * @deprecated 4.0 - */ -const JROUTER_MODE_RAW = 0; - -/** - * Mask for the SEF routing mode - * - * @deprecated 4.0 - */ -const JROUTER_MODE_SEF = 1; - /** * Class to create and parse routes * @@ -54,24 +40,6 @@ class JRouter */ const PROCESS_AFTER = 'postprocess'; - /** - * The rewrite mode - * - * @var integer - * @since 1.5 - * @deprecated 4.0 - */ - protected $mode = null; - - /** - * The rewrite mode - * - * @var integer - * @since 1.5 - * @deprecated 4.0 - */ - protected $_mode = null; - /** * An array of variables * @@ -80,15 +48,6 @@ class JRouter */ protected $vars = array(); - /** - * An array of variables - * - * @var array - * @since 1.5 - * @deprecated 4.0 Will convert to $vars - */ - protected $_vars = array(); - /** * An array of rules * @@ -104,22 +63,6 @@ class JRouter 'parsepostprocess' => array(), ); - /** - * An array of rules - * - * @var array - * @since 1.5 - * @deprecated 4.0 Will convert to $rules - */ - protected $_rules = array( - 'buildpreprocess' => array(), - 'build' => array(), - 'buildpostprocess' => array(), - 'parsepreprocess' => array(), - 'parse' => array(), - 'parsepostprocess' => array(), - ); - /** * Caching of processed URIs * @@ -136,25 +79,6 @@ class JRouter */ protected static $instances = array(); - /** - * Class constructor - * - * @param array $options Array of options - * - * @since 1.5 - */ - public function __construct($options = array()) - { - if (array_key_exists('mode', $options)) - { - $this->_mode = $options['mode']; - } - else - { - $this->_mode = JROUTER_MODE_RAW; - } - } - /** * Returns the global JRouter object, only creating it if it * doesn't already exist. @@ -186,7 +110,7 @@ public static function getInstance($client, $options = array()) } else { - self::$instances[$client] = new $classname($options); + self::$instances[$client] = new $classname; } } @@ -196,37 +120,33 @@ public static function getInstance($client, $options = array()) /** * Function to convert a route to an internal URI * - * @param JUri &$uri The uri. + * @param JUri &$uri The uri. + * @param bool $setVars Set the parsed data in the internal + * storage for current-request-URLs * * @return array * * @since 1.5 */ - public function parse(&$uri) + public function parse(&$uri, $setVars = false) { - // Do the preprocess stage of the URL build process - $vars = $this->processParseRules($uri, self::PROCESS_BEFORE); + // Do the preprocess stage of the URL parse process + $this->processParseRules($uri, self::PROCESS_BEFORE); - // Process the parsed variables based on custom defined rules - // This is the main parse stage - $vars += $this->_processParseRules($uri); + // Do the main stage of the URL parse process + $this->processParseRules($uri); - // Parse RAW URL - if ($this->_mode == JROUTER_MODE_RAW) - { - $vars += $this->_parseRawRoute($uri); - } + // Do the postprocess stage of the URL parse process + $this->processParseRules($uri, self::PROCESS_AFTER); - // Parse SEF URL - if ($this->_mode == JROUTER_MODE_SEF) + if ($setVars) { - $vars += $this->_parseSefRoute($uri); - } + $this->setVars($uri->getQuery(true)); - // Do the postprocess stage of the URL build process - $vars += $this->processParseRules($uri, self::PROCESS_AFTER); + return $this->getVars(); + } - return array_merge($this->getVars(), $vars); + return $uri->getQuery(true); } /** @@ -253,21 +173,8 @@ public function build($url) // Do the preprocess stage of the URL build process $this->processBuildRules($uri, self::PROCESS_BEFORE); - // Process the uri information based on custom defined rules. - // This is the main build stage - $this->_processBuildRules($uri); - - // Build RAW URL - if ($this->_mode == JROUTER_MODE_RAW) - { - $this->_buildRawRoute($uri); - } - - // Build SEF URL : mysite/route/index.php?var=x - if ($this->_mode == JROUTER_MODE_SEF) - { - $this->_buildSefRoute($uri); - } + // Do the main stage of the URL build process + $this->processBuildRules($uri); // Do the postprocess stage of the URL build process $this->processBuildRules($uri, self::PROCESS_AFTER); @@ -277,34 +184,6 @@ public function build($url) return $uri; } - /** - * Get the router mode - * - * @return integer - * - * @since 1.5 - * @deprecated 4.0 - */ - public function getMode() - { - return $this->_mode; - } - - /** - * Set the router mode - * - * @param integer $mode The routing mode. - * - * @return void - * - * @since 1.5 - * @deprecated 4.0 - */ - public function setMode($mode) - { - $this->_mode = $mode; - } - /** * Set a router variable, creating it if it doesn't exist * @@ -318,9 +197,9 @@ public function setMode($mode) */ public function setVar($key, $value, $create = true) { - if ($create || array_key_exists($key, $this->_vars)) + if ($create || array_key_exists($key, $this->vars)) { - $this->_vars[$key] = $value; + $this->vars[$key] = $value; } } @@ -338,11 +217,11 @@ public function setVars($vars = array(), $merge = true) { if ($merge) { - $this->_vars = array_merge($this->_vars, $vars); + $this->vars = array_merge($this->vars, $vars); } else { - $this->_vars = $vars; + $this->vars = $vars; } } @@ -359,9 +238,9 @@ public function getVar($key) { $result = null; - if (isset($this->_vars[$key])) + if (isset($this->vars[$key])) { - $result = $this->_vars[$key]; + $result = $this->vars[$key]; } return $result; @@ -376,7 +255,7 @@ public function getVar($key) */ public function getVars() { - return $this->_vars; + return $this->vars; } /** @@ -394,12 +273,12 @@ public function getVars() */ public function attachBuildRule(callable $callback, $stage = self::PROCESS_DURING) { - if (!array_key_exists('build' . $stage, $this->_rules)) + if (!array_key_exists('build' . $stage, $this->rules)) { throw new InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); } - $this->_rules['build' . $stage][] = $callback; + $this->rules['build' . $stage][] = $callback; } /** @@ -417,145 +296,63 @@ public function attachBuildRule(callable $callback, $stage = self::PROCESS_DURIN */ public function attachParseRule(callable $callback, $stage = self::PROCESS_DURING) { - if (!array_key_exists('parse' . $stage, $this->_rules)) + if (!array_key_exists('parse' . $stage, $this->rules)) { throw new InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); } - $this->_rules['parse' . $stage][] = $callback; - } - - /** - * Function to convert a raw route to an internal URI - * - * @param JUri &$uri The raw route - * - * @return boolean - * - * @since 1.5 - * @deprecated 4.0 Attach your logic as rule to the main parse stage - */ - protected function _parseRawRoute(&$uri) - { - return $this->parseRawRoute($uri); - } - - /** - * Function to convert a raw route to an internal URI - * - * @param JUri &$uri The raw route - * - * @return array Array of variables - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main parse stage - */ - protected function parseRawRoute(&$uri) - { - return array(); - } - - /** - * Function to convert a sef route to an internal URI - * - * @param JUri &$uri The sef URI - * - * @return string Internal URI - * - * @since 1.5 - * @deprecated 4.0 Attach your logic as rule to the main parse stage - */ - protected function _parseSefRoute(&$uri) - { - return $this->parseSefRoute($uri); + $this->rules['parse' . $stage][] = $callback; } /** - * Function to convert a sef route to an internal URI + * Remove a rule * - * @param JUri &$uri The sef URI + * @param string $type Type of rule to remove (parse or build) + * @param callable $rule The rule to be removed. + * @param string $stage The stage of the parse process that + * this should be added to. Possible values: + * 'preprocess', '' for the main parse process, + * 'postprocess' * - * @return array Array of variables + * @return boolean Was a rule removed? * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main parse stage + * @since 4.0 */ - protected function parseSefRoute(&$uri) + public function detachRule($type, $rule, $stage = self::PROCESS_DURING) { - return array(); - } + if (!in_array($type, array('parse', 'build'))) + { + throw new InvalidArgumentException(sprintf('The %s type is not supported. (%s)', $type, __METHOD__)); + } - /** - * Function to build a raw route - * - * @param JUri &$uri The internal URL - * - * @return string Raw Route - * - * @since 1.5 - * @deprecated 4.0 Attach your logic as rule to the main build stage - */ - protected function _buildRawRoute(&$uri) - { - return $this->buildRawRoute($uri); - } + if (!array_key_exists($type . $stage, $this->rules)) + { + throw new InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); + } - /** - * Function to build a raw route - * - * @param JUri &$uri The internal URL - * - * @return string Raw Route - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main build stage - */ - protected function buildRawRoute(&$uri) - { - } + foreach ($this->rules[$type . $stage] as $id => $r) + { + if ($r == $rule) + { + unset($this->rules[$type . $stage][$id]); - /** - * Function to build a sef route - * - * @param JUri &$uri The uri - * - * @return string The SEF route - * - * @since 1.5 - * @deprecated 4.0 Attach your logic as rule to the main build stage - */ - protected function _buildSefRoute(&$uri) - { - return $this->buildSefRoute($uri); - } + return true; + } + } - /** - * Function to build a sef route - * - * @param JUri &$uri The uri - * - * @return string The SEF route - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main build stage - */ - protected function buildSefRoute(&$uri) - { + return false; } /** - * Process the parsed router variables based on custom defined rules + * Get all currently attached rules * - * @param JUri &$uri The URI to parse + * @return array All currently attached rules in an array * - * @return array The array of processed URI variables - * - * @since 1.5 - * @deprecated 4.0 Use processParseRules() instead + * @since 4.0 */ - protected function _processParseRules(&$uri) + public function getRules() { - return $this->processParseRules($uri); + return $this->rules; } /** @@ -572,34 +369,15 @@ protected function _processParseRules(&$uri) */ protected function processParseRules(&$uri, $stage = self::PROCESS_DURING) { - if (!array_key_exists('parse' . $stage, $this->_rules)) + if (!array_key_exists('parse' . $stage, $this->rules)) { throw new InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); } - $vars = array(); - - foreach ($this->_rules['parse' . $stage] as $rule) + foreach ($this->rules['parse' . $stage] as $rule) { - $vars += (array) call_user_func_array($rule, array(&$this, &$uri)); + call_user_func_array($rule, array(&$this, &$uri)); } - - return $vars; - } - - /** - * Process the build uri query data based on custom defined rules - * - * @param JUri &$uri The URI - * - * @return void - * - * @since 1.5 - * @deprecated 4.0 Use processBuildRules() instead - */ - protected function _processBuildRules(&$uri) - { - $this->processBuildRules($uri); } /** @@ -616,33 +394,17 @@ protected function _processBuildRules(&$uri) */ protected function processBuildRules(&$uri, $stage = self::PROCESS_DURING) { - if (!array_key_exists('build' . $stage, $this->_rules)) + if (!array_key_exists('build' . $stage, $this->rules)) { throw new InvalidArgumentException(sprintf('The %s stage is not registered. (%s)', $stage, __METHOD__)); } - foreach ($this->_rules['build' . $stage] as $rule) + foreach ($this->rules['build' . $stage] as $rule) { call_user_func_array($rule, array(&$this, &$uri)); } } - /** - * Create a uri based on a full or partial url string - * - * @param string $url The URI - * - * @return JUri - * - * @since 1.5 - * @deprecated 4.0 Use createUri() instead - * @codeCoverageIgnore - */ - protected function _createUri($url) - { - return $this->createUri($url); - } - /** * Create a uri based on a full or partial url string * @@ -691,80 +453,4 @@ protected function createUri($url) return $uri; } - - /** - * Encode route segments - * - * @param array $segments An array of route segments - * - * @return array Array of encoded route segments - * - * @since 1.5 - * @deprecated 4.0 This should be performed in the component router instead - * @codeCoverageIgnore - */ - protected function _encodeSegments($segments) - { - return $this->encodeSegments($segments); - } - - /** - * Encode route segments - * - * @param array $segments An array of route segments - * - * @return array Array of encoded route segments - * - * @since 3.2 - * @deprecated 4.0 This should be performed in the component router instead - */ - protected function encodeSegments($segments) - { - $total = count($segments); - - for ($i = 0; $i < $total; $i++) - { - $segments[$i] = str_replace(':', '-', $segments[$i]); - } - - return $segments; - } - - /** - * Decode route segments - * - * @param array $segments An array of route segments - * - * @return array Array of decoded route segments - * - * @since 1.5 - * @deprecated 4.0 This should be performed in the component router instead - * @codeCoverageIgnore - */ - protected function _decodeSegments($segments) - { - return $this->decodeSegments($segments); - } - - /** - * Decode route segments - * - * @param array $segments An array of route segments - * - * @return array Array of decoded route segments - * - * @since 3.2 - * @deprecated 4.0 This should be performed in the component router instead - */ - protected function decodeSegments($segments) - { - $total = count($segments); - - for ($i = 0; $i < $total; $i++) - { - $segments[$i] = preg_replace('/-/', ':', $segments[$i], 1); - } - - return $segments; - } } diff --git a/libraries/cms/router/site.php b/libraries/cms/router/site.php index 151284970a083..af42ee2bde60a 100644 --- a/libraries/cms/router/site.php +++ b/libraries/cms/router/site.php @@ -43,40 +43,81 @@ class JRouterSite extends JRouter /** * Class constructor * - * @param array $options Array of options - * @param JApplicationCms $app JApplicationCms Object - * @param JMenu $menu JMenu object + * @param JApplicationCms $app JApplicationCms Object + * @param JMenu $menu JMenu object * * @since 3.4 */ - public function __construct($options = array(), JApplicationCms $app = null, JMenu $menu = null) + public function __construct(JApplicationCms $app = null, JMenu $menu = null) { - parent::__construct($options); - $this->app = $app ? $app : JApplicationCms::getInstance('site'); $this->menu = $menu ? $menu : $this->app->getMenu(); + + // Add core rules + if ($this->app->get('force_ssl') == 2) + { + $this->attachParseRule(array($this, 'parseCheckSSL'), self::PROCESS_BEFORE); + } + + $this->attachParseRule(array($this, 'parseInit'), self::PROCESS_BEFORE); + $this->attachBuildRule(array($this, 'buildInit'), self::PROCESS_BEFORE); + $this->attachBuildRule(array($this, 'buildComponentPreprocess'), self::PROCESS_BEFORE); + + if ($this->app->get('sef')) + { + if ($this->app->get('sef_suffix')) + { + $this->attachParseRule(array($this, 'parseFormat'), self::PROCESS_BEFORE); + $this->attachBuildRule(array($this, 'buildFormat'), self::PROCESS_AFTER); + } + + $this->attachParseRule(array($this, 'parseSefRoute'), self::PROCESS_DURING); + $this->attachBuildRule(array($this, 'buildSefRoute'), self::PROCESS_DURING); + $this->attachParseRule(array($this, 'parsePaginationData'), self::PROCESS_AFTER); + $this->attachBuildRule(array($this, 'buildPaginationData'), self::PROCESS_AFTER); + + if ($this->app->get('sef_rewrite')) + { + $this->attachBuildRule(array($this, 'buildRewrite'), self::PROCESS_AFTER); + } + } + + $this->attachParseRule(array($this, 'parseRawRoute'), self::PROCESS_DURING); + $this->attachBuildRule(array($this, 'buildBase'), self::PROCESS_AFTER); } /** - * Function to convert a route to an internal URI - * - * @param JUri &$uri The uri. + * Force to SSL + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @return array - * - * @since 1.5 + * @return void + * + * @since 4.0 */ - public function parse(&$uri) + public function parseCheckSSL(&$router, &$uri) { - $vars = array(); - - if ($this->app->get('force_ssl') == 2 && strtolower($uri->getScheme()) != 'https') + if (strtolower($uri->getScheme()) != 'https') { // Forward to https $uri->setScheme('https'); $this->app->redirect((string) $uri, 301); } + } + /** + * Do some initial cleanup before parsing the URL + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process + * + * @return void + * + * @since 4.0 + */ + public function parseInit(&$router, &$uri) + { // Get the path // Decode URL to convert percent-encoding to unicode so that strings match when routing. $path = urldecode($uri->getPath()); @@ -100,200 +141,51 @@ public function parse(&$uri) } } - // Identify format - if ($this->_mode == JROUTER_MODE_SEF) - { - if ($this->app->get('sef_suffix') && !(substr($path, -9) == 'index.php' || substr($path, -1) == '/')) - { - if ($suffix = pathinfo($path, PATHINFO_EXTENSION)) - { - $vars['format'] = $suffix; - } - } - } - // Set the route $uri->setPath(trim($path, '/')); - - // Set the parsepreprocess components methods - $components = JComponentHelper::getComponents(); - - foreach ($components as $component) - { - $componentRouter = $this->getComponentRouter($component->option); - - if (method_exists($componentRouter, 'parsepreprocess')) - { - $this->attachParseRule(array($componentRouter, 'parsepreprocess'), static::PROCESS_BEFORE); - } - } - - $vars += parent::parse($uri); - - return $vars; } /** - * Function to convert an internal URI to a route + * Parse the format of the request + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @param string $url The internal URL - * - * @return string The absolute search engine friendly URL - * - * @since 1.5 + * @return void + * + * @since 4.0 */ - public function build($url) + public function parseFormat(&$router, &$uri) { - $uri = parent::build($url); - - // Get the path data $route = $uri->getPath(); - // Add the suffix to the uri - if ($this->_mode == JROUTER_MODE_SEF && $route) - { - if ($this->app->get('sef_suffix') && !(substr($route, -9) == 'index.php' || substr($route, -1) == '/')) - { - if ($format = $uri->getVar('format', 'html')) - { - $route .= '.' . $format; - $uri->delVar('format'); - } - } - - if ($this->app->get('sef_rewrite')) - { - // Transform the route - if ($route == 'index.php') - { - $route = ''; - } - else - { - $route = str_replace('index.php/', '', $route); - } - } - } - - // Add basepath to the uri - $uri->setPath(JUri::base(true) . '/' . $route); - - return $uri; - } - - /** - * Function to convert a raw route to an internal URI - * - * @param JUri &$uri The raw route - * - * @return array - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main parse stage - */ - protected function parseRawRoute(&$uri) - { - $vars = array(); - - // Handle an empty URL (special case) - if (!$uri->getVar('Itemid') && !$uri->getVar('option')) - { - $item = $this->menu->getDefault($this->app->getLanguage()->getTag()); - - if (!is_object($item)) - { - // No default item set - return $vars; - } - - // Set the information in the request - $vars = $item->query; - - // Get the itemid - $vars['Itemid'] = $item->id; - - // Set the active menu item - $this->menu->setActive($vars['Itemid']); - - return $vars; - } - - // Get the variables from the uri - $this->setVars($uri->getQuery(true)); - - // Get the itemid, if it hasn't been set force it to null - $this->setVar('Itemid', $this->app->input->getInt('Itemid', null)); - - // Only an Itemid OR if filter language plugin set? Get the full information from the itemid - if (count($this->getVars()) == 1 || ($this->app->getLanguageFilter() && count($this->getVars()) == 2)) + // Identify format + if (!(substr($route, -9) == 'index.php' || substr($route, -1) == '/') && $suffix = pathinfo($route, PATHINFO_EXTENSION)) { - $item = $this->menu->getItem($this->getVar('Itemid')); - - if ($item !== null && is_array($item->query)) - { - $vars = $vars + $item->query; - } + $uri->setVar('format', $suffix); + $route = str_replace('.' . $suffix, '', $route); + $uri->setPath($route); } - - // Set the active menu item - $this->menu->setActive($this->getVar('Itemid')); - - return $vars; } /** - * Function to convert a sef route to an internal URI + * Convert a sef route to an internal URI * - * @param JUri &$uri The sef URI + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @return string Internal URI - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main parse stage + * @return void + * + * @since 4.0 */ - protected function parseSefRoute(&$uri) + public function parseSefRoute(&$router, &$uri) { $route = $uri->getPath(); - // Remove the suffix - if ($this->app->get('sef_suffix')) - { - if ($suffix = pathinfo($route, PATHINFO_EXTENSION)) - { - $route = str_replace('.' . $suffix, '', $route); - } - } - - // Get the variables from the uri - $vars = $uri->getQuery(true); - - // Handle an empty URL (special case) + // If the URL is empty, we handle this in the non-SEF parse URL if (empty($route)) { - // If route is empty AND option is set in the query, assume it's non-sef url, and parse apropriately - if (isset($vars['option']) || isset($vars['Itemid'])) - { - return $this->parseRawRoute($uri); - } - - $item = $this->menu->getDefault($this->app->getLanguage()->getTag()); - - // If user not allowed to see default menu item then avoid notices - if (is_object($item)) - { - // Set the information in the request - $vars = $item->query; - - // Get the itemid - $vars['Itemid'] = $item->id; - - // Set the active menu item - $this->menu->setActive($vars['Itemid']); - - $this->setVars($vars); - } - - return $vars; + return; } // Parse the application route @@ -301,8 +193,8 @@ protected function parseSefRoute(&$uri) if (count($segments) > 1 && $segments[0] == 'component') { - $vars['option'] = 'com_' . $segments[1]; - $vars['Itemid'] = null; + $uri->setVar('option', 'com_' . $segments[1]); + $uri->setVar('Itemid', null); $route = implode('/', array_slice($segments, 2)); } else @@ -365,74 +257,133 @@ protected function parseSefRoute(&$uri) } else { - $route = substr($route, strlen($found->route)); - - if ($route) - { - $route = substr($route, 1); - } + $route = trim(substr($route, strlen($found->route)), '/'); } if ($found) { - $vars['Itemid'] = $found->id; - $vars['option'] = $found->component; + $uri->setVar('Itemid', $found->id); + $uri->setVar('option', $found->component); } } // Set the active menu item - if (isset($vars['Itemid'])) + if ($uri->getVar('Itemid')) { - $this->menu->setActive($vars['Itemid']); + $this->menu->setActive($uri->getVar('Itemid')); } - // Set the variables - $this->setVars($vars); - // Parse the component route - if (!empty($route) && isset($this->_vars['option'])) + if (!empty($route) && $uri->getVar('option')) { $segments = explode('/', $route); - if (empty($segments[0])) + if (count($segments)) { - array_shift($segments); + // Handle component route + $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $uri->getVar('option')); + $crouter = $this->getComponentRouter($component); + $uri->setQuery(array_merge($uri->getQuery(true), $crouter->parse($segments))); } - // Handle component route - $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $this->_vars['option']); + $route = implode('/', $segments); + } - if (count($segments)) - { - $crouter = $this->getComponentRouter($component); - $vars = $crouter->parse($segments); + $uri->setPath($route); + } - $this->setVars($vars); - } + /** + * Convert a raw route to an internal URI + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process + * + * @return void + * + * @since 4.0 + */ + public function parseRawRoute(&$router, &$uri) + { + if ($uri->getVar('Itemid')) + { + $item = $this->menu->getItem($uri->getVar('Itemid')); } else { - // Set active menu item - if ($item = $this->menu->getActive()) - { - $vars = $item->query; - } + $item = $this->menu->getDefault($this->app->getLanguage()->getTag()); } - return $vars; + if (is_object($item)) + { + // Set the active menu item + $this->menu->setActive($item->id); + + $uri->setVar('Itemid', $item->id); + $uri->setQuery(array_merge($item->query, $uri->getQuery(true))); + } + } + + /** + * Convert limits for pagination + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process + * + * @return void + * + * @since 4.0 + */ + public function parsePaginationData(&$router, &$uri) + { + // Process the pagination support + if ($uri->getVar('start')) + { + $uri->setVar('limitstart', $uri->getVar('start')); + $uri->delVar('start'); + } } /** - * Function to build a raw route + * Do some initial processing for building a URL * - * @param JUri &$uri The internal URL + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @return string Raw Route + * @return void + * + * @since 4.0 + */ + public function buildInit(&$router, &$uri) + { + $itemid = $uri->getVar('Itemid'); + + // If no Itemid and option given, merge in the current requests data + if (!$itemid && !$uri->getVar('option')) + { + $uri->setQuery(array_merge($this->getVars(), $uri->getQuery(true))); + } + + // If Itemid is given, but no option, set the option from the menu item + if ($itemid && !$uri->getVar('option')) + { + if ($item = $this->menu->getItem($itemid)) + { + $uri->setVar('option', $item->component); + } + } + } + + /** + * Run the component preprocess method * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main build stage + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process + * + * @return void + * + * @since 4.0 */ - protected function buildRawRoute(&$uri) + public function buildComponentPreprocess(&$router, &$uri) { // Get the query data $query = $uri->getQuery(true); @@ -446,36 +397,29 @@ protected function buildRawRoute(&$uri) $crouter = $this->getComponentRouter($component); $query = $crouter->preprocess($query); - $uri->setQuery($query); - } + // Make sure any menu vars are used if no others are specified + if (isset($query['Itemid']) + && (count($query) == 2 || (count($query) == 3 && isset($query['lang'])))) + { + // Get the active menu item + $item = $this->menu->getItem($query['Itemid']); + $query = array_merge($item->query, $query); + } - /** - * Function to build a sef route - * - * @param JUri &$uri The internal URL - * - * @return void - * - * @since 1.5 - * @deprecated 4.0 Attach your logic as rule to the main build stage - * @codeCoverageIgnore - */ - protected function _buildSefRoute(&$uri) - { - $this->buildSefRoute($uri); + $uri->setQuery($query); } /** - * Function to build a sef route + * Build the SEF route * - * @param JUri &$uri The uri + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * * @return void - * - * @since 3.2 - * @deprecated 4.0 Attach your logic as rule to the main build stage + * + * @since 4.0 */ - protected function buildSefRoute(&$uri) + public function buildSefRoute(&$router, &$uri) { // Get the route $route = $uri->getPath(); @@ -491,19 +435,19 @@ protected function buildSefRoute(&$uri) // Build the component route $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $query['option']); $tmp = ''; - $itemID = !empty($query['Itemid']) ? $query['Itemid'] : null; + $Itemid = isset($query['Itemid']) ? $query['Itemid'] : null; $crouter = $this->getComponentRouter($component); $parts = $crouter->build($query); - $result = implode('/', $parts); - $tmp = ($result != "") ? $result : ''; - - // Build the application route - $built = false; + $tmp = trim(implode('/', $parts)); - if (!empty($query['Itemid'])) + if (empty($query['Itemid']) && !empty($Itemid)) { - $item = $this->menu->getItem($query['Itemid']); + $query['Itemid'] = $Itemid; + } + // Build the application route + if (isset($query['Itemid']) && $item = $this->menu->getItem($query['Itemid'])) + { if (is_object($item) && $query['option'] == $item->component) { if (!$item->home) @@ -511,204 +455,108 @@ protected function buildSefRoute(&$uri) $tmp = !empty($tmp) ? $item->route . '/' . $tmp : $item->route; } - $built = true; + unset($query['Itemid']); } } - - if (empty($query['Itemid']) && !empty($itemID)) - { - $query['Itemid'] = $itemID; - } - - if (!$built) + else { $tmp = 'component/' . substr($query['option'], 4) . '/' . $tmp; } - if ($tmp) - { - $route .= '/' . $tmp; - } + $route .= '/' . $tmp; // Unset unneeded query information - if (isset($item) && $query['option'] == $item->component) - { - unset($query['Itemid']); - } - unset($query['option']); // Set query again in the URI $uri->setQuery($query); - $uri->setPath($route); + $uri->setPath(trim($route, '/')); } /** - * Process the parsed router variables based on custom defined rules - * - * @param JUri &$uri The URI to parse - * @param string $stage The stage that should be processed. - * Possible values: 'preprocess', 'postprocess' - * and '' for the main parse stage + * Convert limits for pagination * - * @return array The array of processed URI variables + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @since 3.2 + * @return void + * + * @since 4.0 */ - protected function processParseRules(&$uri, $stage = self::PROCESS_DURING) + public function buildPaginationData(&$router, &$uri) { - // Process the attached parse rules - $vars = parent::processParseRules($uri, $stage); - - if ($stage == self::PROCESS_DURING) + if ($uri->getVar('limitstart')) { - // Process the pagination support - if ($this->_mode == JROUTER_MODE_SEF) - { - if ($start = $uri->getVar('start')) - { - $uri->delVar('start'); - $vars['limitstart'] = $start; - } - } + $uri->setVar('start', (int) $uri->getVar('limitstart')); + $uri->delVar('limitstart'); } - - return $vars; } /** - * Process the build uri query data based on custom defined rules - * - * @param JUri &$uri The URI - * @param string $stage The stage that should be processed. - * Possible values: 'preprocess', 'postprocess' - * and '' for the main build stage + * Build the format of the request + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * * @return void - * - * @since 3.2 - * @deprecated 4.0 The special logic should be implemented as rule + * + * @since 4.0 */ - protected function processBuildRules(&$uri, $stage = self::PROCESS_DURING) + public function buildFormat(&$router, &$uri) { - if ($stage == self::PROCESS_DURING) - { - // Make sure any menu vars are used if no others are specified - $query = $uri->getQuery(true); - if ($this->_mode != 1 - && isset($query['Itemid']) - && (count($query) == 2 || (count($query) == 3 && isset($query['lang'])))) - { - // Get the active menu item - $itemid = $uri->getVar('Itemid'); - $lang = $uri->getVar('lang'); - $item = $this->menu->getItem($itemid); - - if ($item) - { - $uri->setQuery($item->query); - } - - $uri->setVar('Itemid', $itemid); - - if ($lang) - { - $uri->setVar('lang', $lang); - } - } - } - - // Process the attached build rules - parent::processBuildRules($uri, $stage); - - if ($stage == self::PROCESS_BEFORE) - { - // Get the query data - $query = $uri->getQuery(true); - - if (!isset($query['option'])) - { - return; - } - - // Build the component route - $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $query['option']); - $router = $this->getComponentRouter($component); - $query = $router->preprocess($query); - $uri->setQuery($query); - } + $route = $uri->getPath(); - if ($stage == self::PROCESS_DURING) + // Identify format + if (!(substr($route, -9) == 'index.php' || substr($route, -1) == '/') && $format = $uri->getVar('format', 'html')) { - // Get the path data - $route = $uri->getPath(); - - if ($this->_mode == JROUTER_MODE_SEF && $route) - { - if ($limitstart = $uri->getVar('limitstart')) - { - $uri->setVar('start', (int) $limitstart); - $uri->delVar('limitstart'); - } - } - + $route .= '.' . $format; $uri->setPath($route); + $uri->delVar('format'); } } /** - * Create a uri based on a full or partial url string + * Cleanup the URL build * - * @param string $url The URI + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process * - * @return JUri - * - * @since 3.2 + * @return void + * + * @since 4.0 */ - protected function createUri($url) + public function buildRewrite(&$router, &$uri) { - // Create the URI - $uri = parent::createUri($url); - - // Get the itemid form the URI - $itemid = $uri->getVar('Itemid'); + // Get the path data + $route = $uri->getPath(); - if (is_null($itemid)) + // Transform the route + if ($route == 'index.php') { - if ($option = $uri->getVar('option')) - { - $item = $this->menu->getItem($this->getVar('Itemid')); - - if (isset($item) && $item->component == $option) - { - $uri->setVar('Itemid', $item->id); - } - } - else - { - if ($option = $this->getVar('option')) - { - $uri->setVar('option', $option); - } - - if ($itemid = $this->getVar('Itemid')) - { - $uri->setVar('Itemid', $itemid); - } - } + $route = ''; } else { - if (!$uri->getVar('option')) - { - if ($item = $this->menu->getItem($itemid)) - { - $uri->setVar('option', $item->component); - } - } + $route = str_replace('index.php/', '', $route); } - return $uri; + $uri->setPath($route); + } + + /** + * Add the basepath to the URI + * + * @param JRouterSite &$router Router object + * @param JUri &$uri URI object to process + * + * @return void + * + * @since 4.0 + */ + public function buildBase(&$router, &$uri) + { + // Add basepath to the uri + $uri->setPath(JUri::base(true) . '/' . $uri->getPath()); } /** diff --git a/tests/unit/suites/libraries/cms/router/JRouterSiteTest.php b/tests/unit/suites/libraries/cms/router/JRouterSiteTest.php index f954f7dcc9d3e..c12005435242b 100644 --- a/tests/unit/suites/libraries/cms/router/JRouterSiteTest.php +++ b/tests/unit/suites/libraries/cms/router/JRouterSiteTest.php @@ -45,6 +45,11 @@ protected function setUp() $this->server = $_SERVER; $_SERVER['HTTP_HOST'] = 'mydomain.com'; + + $this->object = new JRouterSite( + $this->getMockCmsApp(), + TestMockMenu::create($this) + ); } /** @@ -59,6 +64,7 @@ protected function tearDown() { $_SERVER = $this->server; unset($this->server); + unset($this->object); parent::tearDown(); } @@ -68,27 +74,83 @@ protected function tearDown() * * @return void * @testdox JRouterSite is a JRouter - * @since 3.4 + * @since 4.0 */ - public function testJRouterSiteIsAJRouter() + public function testConstruct() { - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) + $this->assertInstanceOf('JRouter', $this->object); + + $rules = $this->object->getRules(); + $this->assertTrue(count($rules['parse' . JRouter::PROCESS_BEFORE]) > 0); + $this->assertTrue(count($rules['parse']) > 0); + $this->assertTrue(count($rules['parse' . JRouter::PROCESS_AFTER]) == 0); + $this->assertTrue(count($rules['build' . JRouter::PROCESS_BEFORE]) > 0); + $this->assertTrue(count($rules['build']) == 0); + $this->assertTrue(count($rules['build' . JRouter::PROCESS_AFTER]) > 0); + + $config = array( + array('sef', null, 1), + array('force_ssl', null, 2), + array('sef_suffix', null, 1), + array('sef_rewrite', null, 1) ); + $app = $this->getMockCmsApp(); + $app->method('get')->will($this->returnValueMap($config)); + $object = new JRouterSite($app, $app->getMenu()); + $rules = $object->getRules(); + $this->assertTrue(count($rules['parse' . JRouter::PROCESS_BEFORE]) == 3); + $this->assertTrue(count($rules['parse']) == 2); + $this->assertTrue(count($rules['parse' . JRouter::PROCESS_AFTER]) == 1); + $this->assertTrue(count($rules['build' . JRouter::PROCESS_BEFORE]) == 2); + $this->assertTrue(count($rules['build']) == 1); + $this->assertTrue(count($rules['build' . JRouter::PROCESS_AFTER]) == 4); + } + + /** + * Tests the parseCheckSSL method + * + * @return void + * + * @since 4.0 + */ + public function testParseCheckSSL() + { + $app = $this->getMockCmsApp(); + $app->expects($this->never()) + ->method('redirect'); + $object = new JRouterSite( + $app, + $app->getMenu() + ); + + $uri = new JUri('https://www.example.test'); - $this->assertInstanceOf('JRouter', $object); + // No redirect and no error with a https URL + $object->parseCheckSSL($object, $uri); + + $app = $this->getMockCmsApp(); + $app->expects($this->once()) + ->method('redirect'); + $object = new JRouterSite( + $app, + $app->getMenu() + ); + + $uri = new JUri('http://www.example.test'); + + $object->parseCheckSSL($object, $uri); + + $this->assertEquals('https', $uri->getScheme()); } /** - * Cases for testParse + * Cases for testParseInit * * @return array * - * @since 3.4 + * @since 4.0 */ - public function casesParse() + public function casesParseInit() { $server1 = array( 'HTTP_HOST' => '', @@ -103,7 +165,6 @@ public function casesParse() 'PHP_SELF' => '/joomla/index.php', 'REQUEST_URI' => '/joomla/index.php?var=value 10' ); - $server3 = array( 'HTTP_HOST' => '', 'SCRIPT_NAME' => '', @@ -111,476 +172,82 @@ public function casesParse() 'PHP_SELF' => '', 'REQUEST_URI' => '' ); - return array( - array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), - 'server' => $server1, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expUrl' => '' - ), - array( - 'url' => '/index.php?var1=value1', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), - 'server' => $server1, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expUrl' => 'index.php?var1=value1' - ), - array( - 'url' => 'index.php?var1=value1', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), - 'server' => $server1, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expUrl' => 'index.php?var1=value1' - ), - array( - 'url' => '/joomla/blog/test.json', - 'mode' => JROUTER_MODE_SEF, - 'map' => array(array('sef_suffix', null, '1')), - 'server' => $server1, - 'expVars' => array('format' => 'json', 'option' => 'com_test3', 'Itemid' => '45'), - 'expUrl' => 'joomla/blog/test.json' - ), - array( - 'url' => '/joomla/blog/test.json/', - 'mode' => JROUTER_MODE_SEF, - 'map' => array(array('sef_suffix', null, '1')), - 'server' => $server1, - 'expVars' => array('option' => 'com_test3', 'Itemid' => '45'), - 'expUrl' => 'joomla/blog/test.json' - ), array( 'url' => '/joomla/blog/test%202', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), 'server' => $server1, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), 'expUrl' => 'joomla/blog/test 2' ), - array( - 'url' => '/joomla/blog/test', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), - 'server' => $server2, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expUrl' => 'blog/test' - ), array( 'url' => '/joomla/blog/te%20st', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), 'server' => $server2, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), 'expUrl' => 'blog/te st' ), - array( - 'url' => '/otherfolder/blog/test', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), - 'server' => $server2, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expUrl' => 'older/blog/test' - ), array( 'url' => '/cli/deletefiles.php?var1=value1', - 'mode' => JROUTER_MODE_RAW, - 'map' => array(), 'server' => $server3, - 'expVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), 'expUrl' => '?var1=value1' - ), + ) ); } /** - * Tests the parse method + * Tests the parseInit method * * @param string $url An associative array with variables - * @param integer $mode JROUTER_MODE_RAW or JROUTER_MODE_SEF - * @param array $map An associative array with app config vars * @param array $server An associative array with $_SERVER vars - * @param array $expectedVars Expected vars * @param string $expectedUris Expected URI string - * + * * @return void * - * @dataProvider casesParse - * @testdox URLs are transformed into proper variables - * @since 3.4 + * @dataProvider casesParseInit + * @since 4.0 */ - public function testParse($url, $mode, $map, $server, $expectedVars, $expectedUris) + public function testParseInit($url, $server, $expectedUris) { $_SERVER = array_merge($_SERVER, $server); - $app = $this->getMockCmsApp(); - $app->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($map)); - - $object = new JRouterSite( - array(), - $app, - TestMockMenu::create($this) - ); - - $object->setMode($mode); - $uri = new JUri($url); - $vars = $object->parse($uri); + $this->object->parseInit($this->object, $uri); - $this->assertEquals($expectedVars, $vars); $this->assertEquals($expectedUris, (string)$uri); } /** - * Tests the parse methods redirect + * Tests the parseFormat method * * @return void - * @testdox External URLs trigger a redirect - * @since 3.4 - */ - public function testParseRedirect() - { - $uri = new JUri('http://www.example.com/index.php'); - - $app = $this->getMockCmsApp(); - $app->expects($this->any()) - ->method('get') - ->will($this->returnValue(2)); - $app->expects($this->once()) - ->method('redirect'); - - $object = new JRouterSite( - array(), - $app, - TestMockMenu::create($this) - ); - - $object->parse($uri); - } - - /** - * Cases for testBuild - * - * @return array * - * @since 3.4 + * @testdox Parse formats + * @since 4.0 */ - public function casesBuild() + public function testParseFormat() { - $server1 = array( - 'HTTP_HOST' => '', - 'SCRIPT_NAME' => '', - 'PHP_SELF' => '', - 'REQUEST_URI' => '' - ); - - $server2 = array( - 'HTTP_HOST' => 'www.example.com:80', - 'SCRIPT_NAME' => '/joomla/index.php', - 'PHP_SELF' => '/joomla/index.php', - 'REQUEST_URI' => '/joomla/index.php?var=value 10' - ); - - return array( - array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'vars' => array(), - 'map' => array(), - 'server' => $server1, - 'expected' => '/' - ), - array( - 'url' => 'blog/test', - 'mode' => JROUTER_MODE_RAW, - 'vars' => array(), - 'map' => array(), - 'server' => $server1, - 'expected' => '/blog/test' - ), - array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'vars' => array(), - 'map' => array(), - 'server' => $server2, - 'expected' => '/joomla/' - ), - array( - 'url' => 'blog/test', - 'mode' => JROUTER_MODE_RAW, - 'vars' => array(), - 'map' => array(), - 'server' => $server2, - 'expected' => '/joomla/blog/test' - ), - array( - 'url' => '', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(), - 'server' => $server1, - 'expected' => '/' - ), - array( - 'url' => 'blog/test', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(), - 'server' => $server1, - 'expected' => '/blog/test' - ), - array( - 'url' => '', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(), - 'server' => $server2, - 'expected' => '/joomla/' - ), - array( - 'url' => 'blog/test', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(), - 'server' => $server2, - 'expected' => '/joomla/blog/test' - ), - array( - 'url' => 'index.php', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/' - ), - array( - 'url' => 'index.php/blog/test', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/blog/test' - ), - array( - 'url' => 'index.php', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1)), - 'server' => $server1, - 'expected' => '/' - ), - array( - 'url' => 'index.php/blog/test', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1)), - 'server' => $server1, - 'expected' => '/blog/test' - ), - array( - 'url' => 'index.php?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_suffix', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/index.php?format=json' - ), - array( - 'url' => 'index.php/blog/test?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_suffix', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/index.php/blog/test.json' - ), - array( - 'url' => 'index.php?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_suffix', null, 1)), - 'server' => $server1, - 'expected' => '/index.php?format=json' - ), - array( - 'url' => 'index.php/blog/test?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_suffix', null, 1)), - 'server' => $server1, - 'expected' => '/index.php/blog/test.json' - ), - array( - 'url' => 'index.php?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1), array('sef_suffix', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/?format=json' - ), - array( - 'url' => 'index.php/blog/test?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1), array('sef_suffix', null, 1)), - 'server' => $server2, - 'expected' => '/joomla/blog/test.json' - ), - array( - 'url' => 'index.php?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1), array('sef_suffix', null, 1)), - 'server' => $server1, - 'expected' => '/?format=json' - ), - array( - 'url' => 'index.php/blog/test?format=json', - 'mode' => JROUTER_MODE_SEF, - 'vars' => array(), - 'map' => array(array('sef_rewrite', null, 1), array('sef_suffix', null, 1)), - 'server' => $server1, - 'expected' => '/blog/test.json' - ), - ); - } - - /** - * testBuild(). - * - * @param string $url The URL - * @param integer $mode JROUTER_MODE_RAW or JROUTER_MODE_SEF - * @param array $vars An associative array with global variables - * @param array $map Valuemap for JApplication::get() Mock - * @param array $server Values for $_SERVER - * @param array $expected Expected value - * - * @dataProvider casesBuild - * - * @return void - * @testdox Variables are transformed into proper URLs - * @since 3.4 - */ - public function testBuild($url, $mode, $vars, $map, $server, $expected) - { - $_SERVER = array_merge($_SERVER, $server); - - $app = $this->getMockCmsApp(); - $app->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($map)); - - $object = new JRouterSite( - array(), - $app, - TestMockMenu::create($this) - ); - - $object->setMode($mode); - - // Check the expected values - $this->assertEquals($expected, (string)($object->build($url))); - } - - /** - * Cases for testParseRawRoute - * - * @return array - * - * @since 3.4 - */ - public function casesParseRawRoute() - { - return array( - 'no_url-sef' => array( - 'url' => '', - 'mode' => JROUTER_MODE_SEF, - 'expParseVars' => array(), - 'expObjVars' => array() - ), - 'no_url-raw-default' => array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'expParseVars' => array('option' => 'com_test3', 'view' => 'test3', 'Itemid' => '45'), - 'expObjVars' => array() - ), - 'url-sef-query-itemid' => array( - 'url' => 'index.php?option=com_test&Itemid=42&testvar=testvalue', - 'mode' => JROUTER_MODE_SEF, - 'expParseVars' => array(), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => '42', 'testvar' => 'testvalue') - ), - 'url-sef-itemid' => array( - 'url' => 'index.php?Itemid=42', - 'mode' => JROUTER_MODE_SEF, - 'expParseVars' => array('option' => 'com_test', 'view' => 'test'), - 'expObjVars' => array('Itemid' => 42) - ), - ); - } - - /** - * Tests the parse method - * - * @param string $url An associative array with variables - * @param integer $mode JROUTER_MODE_RAW or JROUTER_MODE_SEF - * @param array $expectedParseVars An associative array with $_SERVER vars - * @param array $expectedObjectVars An associative array with $_SERVER vars - * - * @return void - * - * @dataProvider casesParseRawRoute - * @since 3.4 - */ - public function testParseRawRoute($url, $mode, $expectedParseVars, $expectedObjectVars) - { - $app = $this->getMockCmsApp(); - - if (isset($expectedObjectVars['Itemid'])) - { - $app->input->set('Itemid', $expectedObjectVars['Itemid']); - } - - if ($mode == JROUTER_MODE_SEF) - { - $menu = TestMockMenu::create($this, false); - $menu - ->expects($this->any()) - ->method('getDefault') - ->will($this->returnValue(null)); - } - else - { - $menu = TestMockMenu::create($this, true); - } - - $object = new JRouterSite( - array(), - $app, - $menu - ); - - $parseRawRouteMethod = new ReflectionMethod('JRouterSite', 'parseRawRoute'); - $parseRawRouteMethod->setAccessible(true); - - $uri = new JUri($url); - $vars = $parseRawRouteMethod->invokeArgs($object, array(&$uri)); - - $this->assertEquals( - $expectedParseVars, - $vars, - "JRouterSite::parseRawRoute() did not return the expected values." - ); - $this->assertEquals( - $expectedObjectVars, - $object->getVars(), - "JRouterSite did not have the expected values internally." - ); + $uri = new JUri('index.php'); + $this->object->parseFormat($this->object, $uri); + + $this->assertEquals('index.php', $uri->getPath()); + $this->assertEquals(array(), $uri->getQuery(true)); + + $uri2 = new JUri('/test/'); + $this->object->parseFormat($this->object, $uri2); + $this->assertEquals('/test/', $uri2->getPath()); + $this->assertEquals(array(), $uri2->getQuery(true)); + + $uri3 = new JUri('/test.html'); + $this->object->parseFormat($this->object, $uri3); + $this->assertEquals('/test', $uri3->getPath()); + $this->assertEquals(array('format' => 'html'), $uri3->getQuery(true)); + + $uri4 = new JUri('/test.json'); + $this->object->parseFormat($this->object, $uri4); + $this->assertEquals('/test', $uri4->getPath()); + $this->assertEquals(array('format' => 'json'), $uri4->getQuery(true)); + + $uri5 = new JUri('/index.php/test.html'); + $this->object->parseFormat($this->object, $uri5); + $this->assertEquals('/index.php/test', $uri5->getPath()); + $this->assertEquals(array('format' => 'html'), $uri5->getQuery(true)); } /** @@ -588,438 +255,167 @@ public function testParseRawRoute($url, $mode, $expectedParseVars, $expectedObje * * @return array * - * @since 3.4 + * @since 4.0 */ public function casesParseSefRoute() { return array( // Empty URLs without a default menu item return nothing 'empty-sef' => array( - 'url' => '', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array() + '', + '' ), // Absolute URLs to the domain of the site + 'matching-menu' => array( + 'test', + '?Itemid=42&option=com_test' + ), 'abs-sef-path-no_qs-no_sfx' => array( - 'url' => '/test/path', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array() + 'test/path', + 'path?Itemid=42&option=com_test' + ), + 'abs-sef-path-no_qs-no' => array( + 'path', + 'path?Itemid=45&option=com_test3' ), 'abs-sef-path-qs-no_sfx' => array( - 'url' => '/test/path?testvar=testvalue', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue') + 'test/path?testvar=testvalue', + 'path?testvar=testvalue&Itemid=42&option=com_test' ), 'abs-sef-no_path-qs-no_sfx' => array( - 'url' => '?testvar=testvalue', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array() - ), - 'abs-sef-path.ext-no_qs-no_sfx' => array( - 'url' => '/test/path.json', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array() - ), - 'abs-sef-path.ext-qs-no_sfx' => array( - 'url' => '/test/path.json?testvar=testvalue', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue') - ), - 'abs-sef-path.ext-no_qs-sfx' => array( - 'url' => '/test/path.json', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(array('sef_suffix', null, '1')), - 'expParseVars' => array(), - 'expObjVars' => array() - ), - 'abs-sef-path.ext-qs-sfx' => array( - 'url' => '/test/path.json?testvar=testvalue', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(array('sef_suffix', null, '1')), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue') - ), - 'empty-raw' => array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('Itemid' => '45', 'option' => 'com_test3', 'view' => 'test3'), - 'expObjVars' => array('Itemid' => '45', 'option' => 'com_test3', 'view' => 'test3') - ), - 'abs-raw-path-no_qs-no_sfx' => array( - 'url' => '/test/path', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('Itemid' => '45', 'option' => 'com_test3') - ), - 'abs-raw-path-qs-no_sfx' => array( - 'url' => '/test/path?testvar=testvalue', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('testvar' => 'testvalue', 'Itemid' => '45', 'option' => 'com_test3') - ), - 'abs-raw-no_path-qs-no_sfx' => array( - 'url' => '?testvar=testvalue', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('Itemid' => '45', 'option' => 'com_test3', 'view' => 'test3'), - 'expObjVars' => array('Itemid' => '45', 'option' => 'com_test3', 'view' => 'test3') - ), - 'abs-raw-path.ext-no_qs-no_sfx' => array( - 'url' => '/test/path.json', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('Itemid' => '45', 'option' => 'com_test3') - ), - 'abs-raw-path.ext-qs-no_sfx' => array( - 'url' => '/test/path.json?testvar=testvalue', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('testvar' => 'testvalue', 'Itemid' => '45', 'option' => 'com_test3') - ), - 'abs-raw-path.ext-no_qs-sfx' => array( - 'url' => '/test/path.json', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(array('sef_suffix', null, '1')), - 'expParseVars' => array(), - 'expObjVars' => array('Itemid' => '45', 'option' => 'com_test3') - ), - 'abs-raw-path.ext-qs-sfx' => array( - 'url' => '/test/path.json?testvar=testvalue', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(array('sef_suffix', null, '1')), - 'expParseVars' => array(), - 'expObjVars' => array('testvar' => 'testvalue', 'Itemid' => '45', 'option' => 'com_test3') - ), - // Non-SEF URLs - 'raw-sef-no_id-no_opt' => array( - 'url' => '?option=com_test', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) - ), - 'raw-sef-id-no_opt' => array( - 'url' => '?Itemid=42', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('Itemid' => null) - ), - 'raw-sef-id-opt' => array( - 'url' => '?Itemid=42&option=com_test', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) - ), - 'raw-raw-no_id-opt' => array( - 'url' => '?option=com_test', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) - ), - // 20 - '20-raw-id-no_opt' => array( - 'url' => '?Itemid=42', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('Itemid' => null) - ), - '20-raw-id-opt' => array( - 'url' => '?Itemid=42&option=com_test', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array(), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) + '?testvar=testvalue', + '?testvar=testvalue' ), // URLs with /component/something 'comp-sef-2lvl' => array( - 'url' => 'component/test', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('option' => 'com_test', 'Itemid' => null), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) - ), - 'comp-raw-2lvl' => array( - 'url' => 'component/test', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('option' => 'com_test', 'Itemid' => null), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => null) + 'component/test', + '?option=com_test' ), 'comp-sef-3lvl' => array( - 'url' => 'component/test2/something', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue', 'option' => 'com_test2', 'Itemid' => null) - ), - 'comp-raw-3lvl' => array( - 'url' => 'component/test2/something', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => null, 'testvar' => 'testvalue') - ), - // Parse current menu items - 'curr-sef-no_lang-2lvl' => array( - 'url' => 'test2/sub-menu', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('option' => 'com_test2', 'Itemid' => 44), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-raw-no_lang-2lvl' => array( - 'url' => 'test2/sub-menu', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('option' => 'com_test2', 'Itemid' => 44), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-sef-no_lang-3lvl' => array( - 'url' => 'test2/sub-menu/something', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue', 'option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-raw-no_lang-3lvl' => array( - 'url' => 'test2/sub-menu/something', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array(), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44, 'testvar' => 'testvalue') - ), - 'curr-sef-lang-2lvl' => array( - 'url' => 'test2/sub-menu', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array('languagefilter' => true), - 'expParseVars' => array('option' => 'com_test2', 'Itemid' => 44), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-raw-lang-2lvl' => array( - 'url' => 'test2/sub-menu', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array('languagefilter' => true), - 'expParseVars' => array('option' => 'com_test2', 'Itemid' => 44), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-sef-lang-3lvl' => array( - 'url' => 'test2/sub-menu/something', - 'mode' => JROUTER_MODE_SEF, - 'appConfig' => array('languagefilter' => true), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('testvar' => 'testvalue', 'option' => 'com_test2', 'Itemid' => 44) - ), - 'curr-raw-lang-3lvl' => array( - 'url' => 'test2/sub-menu/something', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array('languagefilter' => true), - 'expParseVars' => array('testvar' => 'testvalue'), - 'expObjVars' => array('option' => 'com_test2', 'Itemid' => 44, 'testvar' => 'testvalue') - ), - 'engl-raw-lang' => array( - 'url' => 'english-test', - 'mode' => JROUTER_MODE_RAW, - 'appConfig' => array('languagefilter' => true), - 'expParseVars' => array('option' => 'com_test', 'view' => 'test2'), - 'expObjVars' => array('option' => 'com_test', 'Itemid' => '47'), - 'itemid' => 47 - ), + 'component/test2/something', + 'something?option=com_test2&testvar=testvalue' + ) ); } /** * Tests the parseSefRoute method * - * @param string $url An associative array with variables - * @param integer $mode JROUTER_MODE_RAW or JROUTER_MODE_SEF - * @param array $appConfig An associative array with app config vars - * @param array $expectedParseVars An associative array with $_SERVER vars - * @param array $expectedObjectVars An associative array with $_SERVER vars - * @param boolean $setActive Flag if the item is the active menu + * @param string $url A URL string + * @param array $expected An expected URL string * * @return void * * @dataProvider casesParseSefRoute * @testdox Parse SEF route - * @since 3.4 + * @since 4.0 */ - public function testParseSefRoute($url, $mode, $appConfig, $expectedParseVars, $expectedObjectVars, $setActive = false) + public function testParseSefRoute($url, $expected) { - $app = $this->getMockCmsApp(); - - if (isset($expectedParseVars['Itemid'])) - { - $app->input->set('Itemid', $expectedParseVars['Itemid']); - } - - if (isset($appConfig['languagefilter'])) - { - $app->expects($this->any()) - ->method('getLanguageFilter') - ->will($this->returnValue(true)); - unset($appConfig['languagefilter']); - } - $app->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($appConfig)); - - if ($mode == JROUTER_MODE_SEF) - { - $menu = TestMockMenu::create($this, false, $setActive); - $menu - ->expects($this->any()) - ->method('getDefault') - ->will($this->returnValue(null)); - } - else - { - $menu = TestMockMenu::create($this, true, $setActive); - } - - $object = new JRouterSite( - array(), - $app, - $menu - ); - - $parseSefRouteMethod = new ReflectionMethod('JRouterSite', 'parseSefRoute'); - $parseSefRouteMethod->setAccessible(true); - $uri = new JUri($url); - $vars = $parseSefRouteMethod->invokeArgs($object, array(&$uri)); + $this->object->parseSefRoute($this->object, $uri); - $this->assertEquals( - $expectedParseVars, - $vars, - "JRouterSite::parseSefRoute() did not return the expected values." - ); - $this->assertEquals( - $expectedObjectVars, - $object->getVars(), - "JRouterSite did not have the expected values internally." - ); + $this->assertEquals($expected, (string) $uri); } /** - * Tests the buildRawRoute() method + * Tests the parseRawRoute method * * @return void - * @testdox JRouterSite::buildRawRoute() does not change a URL without an option - * @since 3.4 + * + * @testdox Build formats + * @since 4.0 */ - public function testBuildRawRoute() + public function testParseRawRoute() { $uri = new JUri('index.php'); + $this->object->parseRawRoute($this->object, $uri); + $this->assertEquals('index.php?option=com_test3&view=test3&Itemid=45', (string) $uri); - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - - $buildRawRouteMethod = new ReflectionMethod('JRouterSite', 'buildRawRoute'); - $buildRawRouteMethod->setAccessible(true); - - $buildRawRouteMethod->invokeArgs($object, array(&$uri)); - $this->assertEquals('index.php', (string)$uri); + $uri = new JUri('index.php?Itemid=43'); + $this->object->parseRawRoute($this->object, $uri); + $this->assertEquals('index.php?option=com_test2&view=test&Itemid=43', (string) $uri); } /** - * Tests the buildRawRoute() method + * Tests the parsePaginationData method * * @return void - * @testdox JRouterSite::buildRawRoute() executes a component router's preprocess method - * @since 3.4 + * + * @testdox Build formats + * @since 4.0 */ - public function testAComponentRoutersPreprocessMethodIsExecuted() + public function testParsePaginationData() { $uri = new JUri('index.php'); + $this->object->parsePaginationData($this->object, $uri); + $this->assertEquals(array(), $uri->getQuery(true)); - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - - $buildRawRouteMethod = new ReflectionMethod('JRouterSite', 'buildRawRoute'); - $buildRawRouteMethod->setAccessible(true); - - $uri->setVar('option', 'com_test'); - $buildRawRouteMethod->invokeArgs($object, array(&$uri)); - $this->assertEquals('index.php?option=com_test&testvar=testvalue', (string)$uri); + $uri = new JUri('/test?start=23wrong'); + $this->object->parsePaginationData($this->object, $uri); + $this->assertEquals(array('limitstart' => '23wrong'), $uri->getQuery(true)); } /** - * Tests the buildRawRoute() method + * Tests the buildInit() method * * @return void - * @testdox JRouterSite::buildRawRoute() sanitizes broken options to get the right router - * @since 3.4 + * @testdox JRouterSite::buildInit() executes a component router's preprocess method + * @since 4.0 */ - public function testABrokenOptionIsProperlySanitisedToGetTheRightRouter() + public function testBuildInit() { - $uri = new JUri('index.php'); - - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - - $buildRawRouteMethod = new ReflectionMethod('JRouterSite', 'buildRawRoute'); - $buildRawRouteMethod->setAccessible(true); - - $uri->setVar('option', 'com_ te?st'); - $uri->delVar('testvar'); - $buildRawRouteMethod->invokeArgs($object, array(&$uri)); - $this->assertEquals('index.php?option=com_ te?st&testvar=testvalue', (string)$uri); + // Assert a URL with option and Itemid is not touched + $uri = new JUri('index.php?option=com_test&Itemid=42'); + $this->object->buildInit($this->object, $uri); + $this->assertEquals('index.php?option=com_test&Itemid=42', (string)$uri); + + // Assert a URL with only an Itemid set gets the right option set in the request + $uri = new JUri('index.php?Itemid=42'); + $this->object->buildInit($this->object, $uri); + $this->assertEquals('index.php?Itemid=42&option=com_test', (string)$uri); + + // Assert current vars are merged into request if no option and Itemid set + $uri = new JUri('index.php?lang=en-GB'); + $this->object->setVar('current', 'var'); + $this->object->buildInit($this->object, $uri); + $this->assertEquals('index.php?current=var&lang=en-GB', (string)$uri); + + // Assert current vars don't overwrite query params of the request + $uri = new JUri('index.php?view=test42&data=42'); + $this->object->setVar('view', 'test'); + $this->object->buildInit($this->object, $uri); + $this->assertEquals('index.php?current=var&view=test42&data=42', (string)$uri); } /** - * Tests the buildRawRoute() method + * Tests the buildComponentPreprocess() method * * @return void - * @testdox JRouterSite::buildRawRoute() executes a legacy component router's preprocess method - * @since 3.4 + * @testdox JRouterSite::buildComponentPreprocess() executes a component router's preprocess method + * @since 4.0 */ - public function testALegacyComponentRoutersPreprocessMethodIsExecuted() + public function testBuildComponentPreprocess() { - $uri = new JUri('index.php'); - - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); + // Assert preprocess exits without option + $uri = new JUri('index.php?test=true'); + $this->object->buildComponentPreprocess($this->object, $uri); + $this->assertEquals('index.php?test=true', (string)$uri); + + // Assert preprocess of Component router is run + $uri = new JUri('index.php?option=com_test'); + $this->object->buildComponentPreprocess($this->object, $uri); + $this->assertEquals('index.php?option=com_test&testvar=testvalue', (string)$uri); - $buildRawRouteMethod = new ReflectionMethod('JRouterSite', 'buildRawRoute'); - $buildRawRouteMethod->setAccessible(true); + // Assert menu query is merged into request + $uri = new JUri('index.php?option=com_test42&Itemid=42'); + $this->object->buildComponentPreprocess($this->object, $uri); + $this->assertEquals('index.php?option=com_test42&view=test&Itemid=42', (string)$uri); - $uri->setVar('option', 'com_test3'); - $uri->delVar('testvar'); - $buildRawRouteMethod->invokeArgs($object, array(&$uri)); - $this->assertEquals('index.php?option=com_test3', (string)$uri); + // Assert menu query is merged into request with language + $uri = new JUri('index.php?option=com_test42&Itemid=42&lang=en-GB'); + $this->object->buildComponentPreprocess($this->object, $uri); + $this->assertEquals('index.php?option=com_test42&view=test&Itemid=42&lang=en-GB', (string)$uri); } /** @@ -1046,7 +442,7 @@ public function casesBuildSefRoute() ), 'A non existing menu item is correctly ignored' => array( 'url' => 'index.php?option=com_test&var1=value1&Itemid=41', - 'expected' => 'index.php/component/test/?var1=value1&Itemid=41' + 'expected' => 'index.php/component/test?var1=value1&Itemid=41' ), 'A menu item with a parent is properly prepended' => array( 'url' => 'index.php?option=com_test&var1=value1&Itemid=46', @@ -1066,11 +462,11 @@ public function casesBuildSefRoute() ), 'A home menu item is treated properly (without vars)' => array( 'url' => 'index.php?Itemid=45&option=com_test3', - 'expected' => 'index.php/component/test3/?Itemid=45' + 'expected' => 'index.php' ), 'A home menu item is treated properly (with vars)' => array( 'url' => 'index.php?Itemid=45&option=com_test3&testvar=testvalue', - 'expected' => 'index.php/component/test3/?testvar=testvalue&Itemid=45' + 'expected' => 'index.php?testvar=testvalue' ), ); } @@ -1091,213 +487,110 @@ public function testBuildSefRoute($url, $expected) { $uri = new JUri($url); - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - - $buildSefRouteMethod = new ReflectionMethod('JRouterSite', 'buildSefRoute'); - $buildSefRouteMethod->setAccessible(true); - $buildSefRouteMethod->invokeArgs($object, array(&$uri)); + $this->object->buildSefRoute($this->object, $uri); $this->assertEquals($expected, (string)$uri); } /** - * Tests the processParseRules() method + * Tests the buildPaginationData method * * @return void * - * @since 3.4 + * @testdox Build formats + * @since 4.0 */ - public function testProcessParseRules() + public function testBuildPaginationData() { - $uri = new JUri('index.php?start=42'); - - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - $object->setMode(JROUTER_MODE_SEF); - - $processParseRulesMethod = new ReflectionMethod('JRouterSite', 'processParseRules'); - $processParseRulesMethod->setAccessible(true); - - $vars = $processParseRulesMethod->invokeArgs($object, array(&$uri)); + $uri = new JUri('index.php'); + $this->object->buildPaginationData($this->object, $uri); + $this->assertEquals(array(), $uri->getQuery(true)); - $this->assertEquals('index.php', $uri->toString()); - $this->assertEquals(array('limitstart' => '42'), $vars); + $uri2 = new JUri('/test?limitstart=23wrong'); + $this->object->buildPaginationData($this->object, $uri2); + $this->assertEquals(array('start' => 23), $uri2->getQuery(true)); } /** - * Cases for testProcessBuildRules + * Tests the buildFormat method * - * @return array + * @return void * - * @since 3.4 + * @testdox Build formats + * @since 4.0 */ - public function casesProcessBuildRules() + public function testBuildFormat() { - return array( - // Check if an empty URL is returned as an empty URL - 'empty' => array( - 'url' => '', - 'mode' => JROUTER_MODE_RAW, - 'expected' => '' - ), - /** - * Check if a URL with an Itemid and another query parameter - * is replaced with the query of the menu item plus the Itemid - * when mode is not SEF - */ - 'raw' => array( - 'url' => 'index.php?Itemid=42&test=true', - 'mode' => JROUTER_MODE_RAW, - 'expected' => 'index.php?option=com_test&view=test&Itemid=42' - ), - /** - * Check if a URL with an Itemid and another query parameter - * is returned identical when mode is SEF - */ - 'sef' => array( - 'url' => 'index.php?Itemid=42&test=true', - 'mode' => JROUTER_MODE_SEF, - 'expected' => 'index.php?Itemid=42&test=true' - ), - /** - * Check if a URL with a path and limitstart gets the limitstart - * parameter converted to start when mode is SEF - */ - 'limitstart' => array( - 'url' => 'test?limitstart=42', - 'mode' => JROUTER_MODE_SEF, - 'expected' => 'test?start=42' - ), - ); + $uri = new JUri('index.php'); + $this->object->buildFormat($this->object, $uri); + $this->assertEquals('index.php', $uri->getPath()); + $this->assertEquals(array(), $uri->getQuery(true)); + + $uri2 = new JUri('/test/'); + $this->object->buildFormat($this->object, $uri2); + $this->assertEquals('/test/', $uri2->getPath()); + $this->assertEquals(array(), $uri2->getQuery(true)); + + $uri3 = new JUri('/test'); + $this->object->buildFormat($this->object, $uri3); + $this->assertEquals('/test.html', $uri3->getPath()); + $this->assertEquals(array(), $uri3->getQuery(true)); + + $uri4 = new JUri('/test?format=json'); + $this->object->buildFormat($this->object, $uri4); + $this->assertEquals('/test.json', $uri4->getPath()); + $this->assertEquals(array(), $uri4->getQuery(true)); + + $uri5 = new JUri('/index.php/test?format=html&test=true'); + $this->object->buildFormat($this->object, $uri5); + $this->assertEquals('/index.php/test.html', $uri5->getPath()); + $this->assertEquals(array('test' => 'true'), $uri5->getQuery(true)); } /** - * testProcessBuildRules(). + * Tests the buildRewrite() method * - * @param string $url Input URL - * @param int $mode - * @param string $expected Expected return value - * - * @dataProvider casesProcessBuildRules + * @return void * - * @since 3.4 + * @since 4.0 */ - public function testProcessBuildRules($url, $mode, $expected) + public function testBuildRewrite() { - $uri = new JUri($url); - - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - $object->setMode($mode); - - $processBuildRulesMethod = new ReflectionMethod('JRouterSite', 'processBuildRules'); - $processBuildRulesMethod->setAccessible(true); - - $processBuildRulesMethod->invokeArgs($object, array(&$uri)); + $uri = new JUri(''); + $this->object->buildRewrite($this->object, $uri); + $this->assertEquals('', $uri->getPath()); - $this->assertEquals($expected, (string)$uri); - } + $uri = new JUri('index.php'); + $this->object->buildRewrite($this->object, $uri); + $this->assertEquals('', $uri->getPath()); - /** - * Cases for testCreateURI - * - * @return array - * - * @since 3.4 - */ - public function casesCreateUri() - { - return array( - // Check if a rather non-URL is returned identical - array( - 'url' => 'index.php?var1=value&var2=value2', - 'preset' => array(), - 'expected' => 'index.php?var1=value&var2=value2' - ), - // Check if a URL with Itemid and option is returned identically - array( - 'url' => 'index.php?option=com_test&Itemid=42&var1=value1', - 'preset' => array(), - 'expected' => 'index.php?option=com_test&Itemid=42&var1=value1' - ), - // Check if a URL with existing Itemid and no option is added the right option - array( - 'url' => 'index.php?Itemid=42&var1=value1', - 'preset' => array(), - 'expected' => 'index.php?Itemid=42&var1=value1&option=com_test' - ), - // Check if a URL with non-existing Itemid and no option is returned identically - array( - 'url' => 'index.php?Itemid=41&var1=value1', - 'preset' => array(), - 'expected' => 'index.php?Itemid=41&var1=value1' - ), - // Check if a URL with no Itemid and no option, but globally set option is added the option - array( - 'url' => 'index.php?var1=value1', - 'preset' => array('option' => 'com_test'), - 'expected' => 'index.php?var1=value1&option=com_test' - ), - // Check if a URL with no Itemid and no option, but globally set Itemid is added the Itemid - array( - 'url' => 'index.php?var1=value1', - 'preset' => array('Itemid' => '42'), - 'expected' => 'index.php?var1=value1&Itemid=42' - ), - // Check if a URL without an Itemid, but with an option set and a global Itemid available, which fits the option of the menu item gets the Itemid appended - array( - 'url' => 'index.php?var1=value&option=com_test', - 'preset' => array('Itemid' => '42'), - 'expected' => 'index.php?var1=value&option=com_test&Itemid=42' - ), - // Check if a URL without an Itemid, but with an option set and a global Itemid available, which does not fit the option of the menu item gets returned identically - array( - 'url' => 'index.php?var1=value&option=com_test3', - 'preset' => array('Itemid' => '42'), - 'expected' => 'index.php?var1=value&option=com_test3' - ), - ); + $uri = new JUri('index.php/test/path/'); + $this->object->buildRewrite($this->object, $uri); + $this->assertEquals('test/path/', $uri->getPath()); } /** - * Tests createUri() method - * - * @param array $url valid inputs to the createUri() method - * @param array $preset global Vars that should be merged into the URL - * @param string $expected expected URI string + * Tests the buildBase() method * - * @dataProvider casesCreateURI + * @return void * - * @return void - * @testdox Create URI - * @since 3.4 + * @since 4.0 */ - public function testCreateUri($url, $preset, $expected) + public function testBuildBase() { - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) + $server = array( + 'HTTP_HOST' => 'www.example.com:80', + 'SCRIPT_NAME' => '/joomla/index.php', + 'PHP_SELF' => '/joomla/index.php', + 'REQUEST_URI' => '/joomla/index.php?var=value 10' ); - $object->setVars($preset); - - $createUriMethod = new ReflectionMethod('JRouterSite', 'createUri'); - $createUriMethod->setAccessible(true); - $uri = $createUriMethod->invoke($object, $url); + $_SERVER = array_merge($_SERVER, $server); - $this->assertInstanceOf('JUri', $uri); - $this->assertEquals($expected, (string)$uri); + $uri = new JUri('index.php'); + $this->assertEquals('index.php', $uri->getPath()); + $this->object->buildBase($this->object, $uri); + $this->assertEquals(JUri::base(true) . '/' . 'index.php', $uri->getPath()); } /** @@ -1309,32 +602,26 @@ public function testCreateUri($url, $preset, $expected) */ public function testGetComponentRouter() { - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - /** * Get the TestRouter and check if you get the * same object instance the second time */ - $router = $object->getComponentRouter('com_test'); + $router = $this->object->getComponentRouter('com_test'); $this->assertInstanceOf('TestRouter', $router); - $this->assertSame($router, $object->getComponentRouter('com_test')); + $this->assertSame($router, $this->object->getComponentRouter('com_test')); /** * Check if a proper router is automatically loaded * by loading the router of com_content */ - $this->assertInstanceOf('ContentRouter', $object->getComponentRouter('com_content')); + $this->assertInstanceOf('ContentRouter', $this->object->getComponentRouter('com_content')); /** * Check if an instance of JComponentRouterLegacy * is returned for non-existing routers */ - $this->assertInstanceOf('JComponentRouterLegacy', $object->getComponentRouter('com_legacy')); + $this->assertInstanceOf('JComponentRouterLegacy', $this->object->getComponentRouter('com_legacy')); } /** @@ -1346,16 +633,10 @@ public function testGetComponentRouter() */ public function testValidRouterGetsAccepted() { - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - $router = new TestRouter; - $this->assertTrue($object->setComponentRouter('com_test', $router)); - $this->assertSame($router, $object->getComponentRouter('com_test')); + $this->assertTrue($this->object->setComponentRouter('com_test', $router)); + $this->assertSame($router, $this->object->getComponentRouter('com_test')); } /** @@ -1367,12 +648,6 @@ public function testValidRouterGetsAccepted() */ public function testInvalidRouterIsRejected() { - $object = new JRouterSite( - array(), - $this->getMockCmsApp(), - TestMockMenu::create($this) - ); - - $this->assertFalse($object->setComponentRouter('com_test3', new stdClass)); + $this->assertFalse($this->object->setComponentRouter('com_test3', new stdClass)); } } diff --git a/tests/unit/suites/libraries/cms/router/JRouterTest.php b/tests/unit/suites/libraries/cms/router/JRouterTest.php index 1ae1026a4bbcd..ed932865e8ea0 100644 --- a/tests/unit/suites/libraries/cms/router/JRouterTest.php +++ b/tests/unit/suites/libraries/cms/router/JRouterTest.php @@ -75,55 +75,24 @@ protected function tearDown() } /** - * @return array - * @since 4.0 - */ - public function casesClients() - { - return array( - // 'site' => array('site'), - 'admin' => array('administrator'), - ); - } - - /** - * @dataProvider casesClients - * @testdox JRouter::getInstance() returns a router of the required type with correct mode - * @since 3.4 - * - * @param $client - */ - public function testProperTypeAndMode($client) - { - $cache = new ReflectionProperty('JRouter', 'instances'); - $cache->setAccessible(true); - $cache->setValue(array()); - - #$this->markTestSkipped('Untestable due to global instance cache not clearable.'); - - $object = JRouter::getInstance($client, array('mode' => 'test')); - - $expected = 'JRouter' . ucfirst($client); - - $this->assertInstanceOf($expected, $object); - $this->assertEquals('test', $object->getMode()); - } - - /** - * @dataProvider casesClients - * @testdox Subsequent calls to getInstance() return the same instance - * @since 3.4 + * Tests the getInstance() method * - * @param $client + * @return void + * @testdox JRouter::getInstance() returns a (cached) instance of a router object + * @since 4.0 */ - public function testSubsequentCallsReturnTheSameInstance($client) + public function testGetInstance() { - $object = JRouter::getInstance($client); + $object = JRouter::getInstance('administrator'); + $this->assertInstanceOf('JRouterAdministrator', $object); - $this->assertSame($object, JRouter::getInstance($client)); + $this->assertSame($object, JRouter::getInstance('administrator')); } /** + * Tests the exception thrown by the getInstance() method + * + * @return void * @since 3.4 * @expectedException RuntimeException * @testdox getInstance() throws a RuntimeException, if a router for an unknown client is requested @@ -134,108 +103,185 @@ public function testGetInstanceException() } /** - * @since 3.4 + * Cases for testParse + * + * @return array + * + * @since 4.0 */ public function casesParse() { return array( - 'raw-no_url-no_var' => array('', JROUTER_MODE_RAW, array(), array()), - 'raw-url-no_var' => array('index.php?var1=value1', JROUTER_MODE_RAW, array(), array()), - 'raw-no_url-var' => array('', JROUTER_MODE_RAW, array('var2' => 'value2'), array('var2' => 'value2')), - 'raw-url-var' => array( - 'index.php?var1=value1', - JROUTER_MODE_RAW, - array('var2' => 'value2'), - array('var2' => 'value2') - ), - 'sef-no_url-no_var' => array('', JROUTER_MODE_SEF, array(), array()), - 'sef-url-no_var' => array('index.php?var1=value1', JROUTER_MODE_SEF, array(), array()), - 'sef-no_url-var' => array('', JROUTER_MODE_SEF, array('var2' => 'value2'), array('var2' => 'value2')), - 'sef-url-var' => array( - 'index.php?var1=value1', - JROUTER_MODE_RAW, - array('var2' => 'value2'), - array('var2' => 'value2') + // Empty URLs create an empty result + 'empty-urls-empty-result' => array( + array(), + array(), + false, + '', + array(), + array() + ), + // Empty URLs and rule can create a result + 'empty-url-rule-nonempty-result' => array( + array( + function (&$router, &$uri) + { + $uri->setVar('result', '1'); + } + ), + array(JRouter::PROCESS_DURING), + false, + '', + array('result' => '1'), + array() + ), + // Vars are stored in the object + 'store-vars-in-object' => array( + array( + function (&$router, &$uri) + { + $uri->setVar('result', '1'); + } + ), + array(JRouter::PROCESS_DURING), + true, + '', + array('result' => '1'), + array('result' => '1') + ), + // absolute URL with no query params returns empty result + 'abs-no-query-no-result' => array( + array(), + array(), + true, + 'http://www.example.test/testsegment', + array(), + array() + ), + // URL with no query params returns empty result + 'no-query-no-result' => array( + array(), + array(), + true, + '/testsegment', + array(), + array() + ), + // URL with query params returns result + 'query-result' => array( + array(), + array(), + false, + '/testsegment?result=1&test=true', + array('result' => '1', 'test' => 'true'), + array() + ), + // URL with query params returns result + 'query-result-setvar' => array( + array(), + array(), + true, + '/testsegment?result=1&test=true', + array('result' => '1', 'test' => 'true'), + array('result' => '1', 'test' => 'true') + ), + // Several rules are applied to one URL + 'several-rules-applied-to-url' => array( + array( + function (&$router, &$uri) + { + $uri->setVar('rule1', '1'); + }, + function (&$router, &$uri) + { + $uri->setVar('rule2', '1'); + } + ), + array(JRouter::PROCESS_DURING, JRouter::PROCESS_DURING), + false, + '/testsegment?result=1&test=true', + array('result' => '1', 'test' => 'true', 'rule1' => '1', 'rule2' => '1'), + array() + ), + // Several rules are applied to one URL - ordered + 'several-rules-applied-to-url-ordered' => array( + array( + function (&$router, &$uri) + { + $uri->setVar('rule1', '1'); + }, + function (&$router, &$uri) + { + $uri->setVar('rule2', '1'); + }, + function (&$router, &$uri) + { + $uri->setVar('rule3', '1'); + } + ), + array(JRouter::PROCESS_AFTER, JRouter::PROCESS_DURING, JRouter::PROCESS_BEFORE), + false, + '/testsegment?result=1&test=true', + array('result' => '1', 'test' => 'true', 'rule3' => '1', 'rule2' => '1', 'rule1' => '1'), + array() + ), + // Several rules are applied to one URL - ordered + 'rules-overwrite-data' => array( + array( + function (&$router, &$uri) + { + $uri->setVar('rule2', '2'); + }, + function (&$router, &$uri) + { + $uri->setVar('rule2', '1'); + } + ), + array(JRouter::PROCESS_AFTER, JRouter::PROCESS_DURING), + false, + '/testsegment?result=1&test=true', + array('result' => '1', 'test' => 'true', 'rule2' => '2'), + array() ), ); } /** - * @param string $url A URL - * @param integer $mode JROUTER_MODE_RAW or JROUTER_MODE_SEF - * @param array $vars An associative array with global variables - * @param array $expected Expected value + * Tests the parse() method * - * @dataProvider casesParse - * @testdox parse() does not evaluate URL parameters - * @since 3.4 + * @dataProvider casesParse + * @return void + * @testdox JRouter::parse() parses a JUri object into an array of parameters + * @since 4.0 */ - public function testRouterDoesNotEvaluateUrlParameters($url, $mode, $vars, $expected) + public function testParse($rules, $stages, $setVars, $url, $expected, $expectedVars) { - $this->object->setMode($mode); - $this->object->setVars($vars); + foreach ($rules as $i => $rule) + { + $this->object->attachParseRule($rule, $stages[$i]); + } + $uri = new JUri($url); + $result = $this->object->parse($uri, $setVars); - $this->assertEquals($this->object->parse($uri), $expected); + $this->assertEquals($expected, $result); + $this->assertEquals($expectedVars, $this->object->getVars()); } /** - * @return array - */ - public function casesModes() - { - return array( - 'default' => array(null), - 'raw' => array(JROUTER_MODE_RAW), - 'sef' => array(JROUTER_MODE_SEF) - ); - } - - /** - * @dataProvider casesModes * @testdox build() gives the same result as the JUri constructor - * @since 3.4 - * - * @param $mode + * @since 4.0 */ - public function testBuildGivesTheSameResultAsTheJuriConstructor($mode) + public function testBuild() { $uri = new JUri('index.php?var1=value1'); $object = new JRouter; - if (!empty($mode)) - { - $object->setMode($mode); - } $result = $this->object->build('index.php?var1=value1'); $this->assertEquals($uri, $result); } - /** - * @testdox Default mode is handling raw URLs - * @since 3.4 - */ - public function testDefaultModeIsHandlingRawUrls() - { - $this->assertEquals(JROUTER_MODE_RAW, $this->object->getMode()); - } - /** - * @since 3.4 - */ - public function testModeCanBeChangedAfterInstantiation() - { - $this->object->setMode(JROUTER_MODE_SEF); - $this->assertEquals(JROUTER_MODE_SEF, $this->object->getMode()); - } - /** - * @since 3.4 - */ - public function testModeCanBeSetToAnyArbitraryValue() - { - $this->object->setMode(42); - $this->assertEquals(42, $this->object->getMode()); - } /** * @see https://github.com/joomla-projects/joomla-pythagoras/issues/3 @@ -315,207 +361,6 @@ public function testRouterThrowsInvalidArgumentExceptionWhenAttachingParseRuleTo $this->object->attachParseRule($callback, 'undefined'); } - /** - * @return array - */ - public function casesParseRulesForReplace() - { - return array( - 'before' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'before'); - } - ), - 'stage' => JRouter::PROCESS_BEFORE, - 'expected' => array('var1' => 'before', 'var2' => 'value2') - ), - 'during' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'during'); - } - ), - 'stage' => JRouter::PROCESS_DURING, - 'expected' => array('var1' => 'during', 'var2' => 'value2') - ), - 'after' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'after'); - } - ), - 'stage' => JRouter::PROCESS_AFTER, - 'expected' => array('var1' => 'after', 'var2' => 'value2') - ), - ); - } - - /** - * @param array $preset Initial router variables - * @param array $rules Callback to execute - * @param string $stage Stage to process - * @param string $expected Expected return value - * - * @dataProvider casesParseRulesForReplace - * @since 3.4 - */ - public function testParseRulesCanReplacePresetVariables($preset, $rules, $stage, $expected) - { - $this->object->setVars($preset, false); - foreach ($rules as $rule) - { - $this->object->attachParseRule($rule, $stage); - } - - $uri = $this->getMock('JUri'); - $this->assertEquals($expected, $this->object->parse($uri)); - } - - /** - * @return array - */ - public function casesParseRulesForAdd() - { - return array( - 'before' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var3' => 'value3'); - }, - ), - 'stage' => JRouter::PROCESS_BEFORE, - 'expected' => array('var1' => 'value1', 'var2' => 'value2', 'var3' => 'value3') - ), - 'during' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var3' => 'value3'); - }, - ), - 'stage' => JRouter::PROCESS_DURING, - 'expected' => array('var1' => 'value1', 'var2' => 'value2', 'var3' => 'value3') - ), - 'after' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var3' => 'value3'); - }, - ), - 'stage' => JRouter::PROCESS_AFTER, - 'expected' => array('var1' => 'value1', 'var2' => 'value2', 'var3' => 'value3') - ), - ); - } - - /** - * @param array $preset Initial router variables - * @param array $rules Callback to execute - * @param string $stage Stage to process - * @param string $expected Expected return value - * - * @dataProvider casesParseRulesForAdd - * @since 3.4 - */ - public function testParseRulesCanAddVariables($preset, $rules, $stage, $expected) - { - $this->object->setVars($preset, false); - foreach ($rules as $rule) - { - $this->object->attachParseRule($rule, $stage); - } - - $uri = $this->getMock('JUri'); - $this->assertEquals($expected, $this->object->parse($uri)); - } - - /** - * @return array - */ - public function casesParseRulesForPrecedence() - { - return array( - 'before-same_var' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'before1'); - }, - function (JRouter $router, JUri $uri) - { - return array('var1' => 'before2'); - }, - ), - 'stage' => JRouter::PROCESS_BEFORE, - 'expected' => array('var1' => 'before1', 'var2' => 'value2') - ), - 'during-same_var' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'during1'); - }, - function (JRouter $router, JUri $uri) - { - return array('var1' => 'during2'); - }, - ), - 'stage' => JRouter::PROCESS_BEFORE, - 'expected' => array('var1' => 'during1', 'var2' => 'value2') - ), - 'after-same_var' => array( - 'preset' => array('var1' => 'value1', 'var2' => 'value2'), - 'rules' => array( - function (JRouter $router, JUri $uri) - { - return array('var1' => 'after1'); - }, - function (JRouter $router, JUri $uri) - { - return array('var1' => 'after2'); - }, - ), - 'stage' => JRouter::PROCESS_BEFORE, - 'expected' => array('var1' => 'after1', 'var2' => 'value2') - ), - ); - } - - /** - * @param array $preset Initial router variables - * @param array $rules Callback to execute - * @param string $stage Stage to process - * @param string $expected Expected return value - * - * @dataProvider casesParseRulesForPrecedence - * @since 3.4 - */ - public function testFirstParseRuleTakesPrecedence($preset, $rules, $stage, $expected) - { - $this->object->setVars($preset, false); - foreach ($rules as $rule) - { - $this->object->attachParseRule($rule, $stage); - } - - $uri = $this->getMock('JUri'); - $this->assertEquals($expected, $this->object->parse($uri)); - } - /** * Cases for testProcessBuildRules * @@ -793,60 +638,66 @@ public function testCreateUriGeneratesUriFromUrlAndPreset($url, $preset, $expect } /** - * @since 3.4 + * Tests the detachRule() method + * + * @return void + * + * @since 4.0 + * @covers JRouter::detachRule */ - public function casesEncodeSegments() + public function testDetachRule() { - return array( - array(array('test'), array('test')), - array(array('1:test'), array('1-test')), - array(array('test', '1:test'), array('test', '1-test')), - array(array('42:test', 'testing:this:method'), array('42-test', 'testing-this-method')), - ); + $rule = function () {}; + $this->object->attachParseRule($rule); + $rules = $this->object->getRules(); + $this->assertEquals(array($rule), $rules['parse']); + $this->assertTrue($this->object->detachRule('parse', $rule)); + $rules = $this->object->getRules(); + $this->assertEquals(array(), $rules['parse']); + $this->assertFalse($this->object->detachRule('parse', $rule)); } /** - * Tests encodeSegments() method - * - * @param array $segments Array of decoded segments of a URL - * @param string $expected Array of encoded segments of a URL - * - * @dataProvider casesEncodeSegments - * @since 3.4 + * @since 4.0 + * @expectedException InvalidArgumentException */ - public function testEncodeSegments($segments, $expected) + public function testDetachRuleWrongType() { - $encodeSegmentsMethod = new ReflectionMethod('JRouter', 'encodeSegments'); - $encodeSegmentsMethod->setAccessible(true); - $this->assertEquals($expected, $encodeSegmentsMethod->invoke($this->object, $segments)); + $rule = function () {}; + $this->object->detachRule('parsewrong', $rule); } /** - * @since 3.4 + * @since 4.0 + * @expectedException InvalidArgumentException */ - public function casesDecodeSegments() + public function testDetachRuleWrongStage() { - return array( - array(array('test'), array('test')), - array(array('1-test'), array('1:test')), - array(array('test', '1-test'), array('test', '1:test')), - array(array('42-test', 'testing-this-method'), array('42:test', 'testing:this-method')), - ); + $rule = function () {}; + $this->object->detachRule('parse', $rule, 'wrong'); } /** - * Tests decodeSegments() method - * - * @param string $encoded Array of encoded segments of a URL - * @param array $expected Array of decoded segments of a URL - * - * @dataProvider casesDecodeSegments - * @since 3.4 + * @since 4.0 + * @expectedException InvalidArgumentException + */ + public function testProcessBuildRules() + { + $uri = new JUri(); + $method = new ReflectionMethod('JRouter', 'processBuildRules'); + $method->setAccessible(true); + $method->invokeArgs($this->object, array(&$uri, 'after')); + } + + /** + * @since 4.0 + * @expectedException InvalidArgumentException */ - public function testDecodeSegments($encoded, $expected) + public function testProcessParseRules() { - $decodeSegmentsMethod = new ReflectionMethod('JRouter', 'decodeSegments'); - $decodeSegmentsMethod->setAccessible(true); - $this->assertEquals($expected, $decodeSegmentsMethod->invoke($this->object, $encoded)); + $uri = new JUri(); + $processParseRulesMethod = new ReflectionMethod('JRouter', 'processParseRules'); + $processParseRulesMethod->setAccessible(true); + $processParseRulesMethod->invokeArgs($this->object, array(&$uri, 'afterwrong')); } }