/** * 测试反向解析 */ function testReservedParse() { $context = QContext::instance(); $router = new QRouter($context); foreach ($this->_tests_args as $offset => $test) { $copy = $test; $path = $test['_path']; unset($test['_path']); $context->module_name = isset($test['module']) ? $test['module'] : null; $context->namespace = isset($test['namespace']) ? $test['namespace'] : null; $context->controller_name = isset($test['controller']) ? $test['controller'] : null; $context->action_name = isset($test['action']) ? $test['action'] : null; $context->setRequestUDI(); $test['module'] = $context->module_name; $test['namespace'] = $context->namespace; $test['controller'] = $context->controller_name; $test['action'] = $context->action_name; $result = $router->url($test); list($route_name) = explode(':', $offset); if ($route_name != $router->reserve_matched_route_name) { QDebug::dump($test, "Expected route name is [{$offset}] : {$path}."); } $this->assertEquals($route_name, $router->reserve_matched_route_name, "Expected route name is [{$route_name}]."); $this->assertEquals($path, $result, print_r($copy, true) . "\n" . print_r($test, true)); } }
/** * 测试反向解析 */ function testReverseParse() { $context = QContext::instance(); $router = new QRouter(); $router->import(Q::ini('routes')); foreach ($this->_tests_args as $offset => $test) { $copy = $test; $path = $test['_path']; unset($test['_path']); $result = $router->url($test); list($route_name) = explode(':', $offset); if ($route_name != $router->lastReverseMatchedRouteName()) { dump('-----------------------------------'); dump($path, 'test path'); dump($test, $result); dump($router->lastReverseMatchedRouteName(), 'used route'); dump($route_name, 'expected route'); dump($router->get($route_name)); } $this->assertEquals($route_name, $router->lastReverseMatchedRouteName(), "Expected route name is [{$route_name}]."); $this->assertEquals($path, $result, "{$path} == {$result}\n" . print_r($copy, true) . "\n" . print_r($test, true)); } }
/** * 构造 url * * 用法: * * @code php * url(UDI, [附加参数数组], [路由名]) * @endcode * * UDI 是统一目的地标识符(Uniform Destination Identifier)的缩写。 * UDI 由控制器、动作、名字空间以及模块名组成,采用如下的格式: * * @code php * ns::controller/action@module * @endcode * * UDI 字符串中,每一个部分都是可选的。 * 如果没有提供控制器和动作名,则使用当前的控制器和默认动作名(index)代替。 * 同样,如果未提供模块名和名字空间,均使用当前值代替。 * * UDI 字符串写法示例: * * @code php * 'controller' * 'controller/action' * '/action' * 'controller@module' * 'controller/action@module' * 'ns::controller' * 'ns::controller/action' * 'ns::controller@module' * 'ns::controller/action@module' * '@module' * 'ns::@module' * @endcode * * 示例: * @code php * url('admin::posts/edit', array('id' => $post->id())); * @endcode * * $params 参数除了采用数组,还可以是以“/”符号分割的字符串: * * @code php * url('posts/index', 'page/3'); * url('users/show', 'id/5/profile/yes'); * @endcode * * 在使用 PATHINFO 和 URL 重写时,可以使用通过制定路由名来强制要求 QeePHP * 采用指定的路由规则来生成 URL。强制指定路由规则可以加快 URL 的生成, * 但在路由规则名称发生变化时,需要修改生成 URL 的代码。 * * $opts 参数用于控制如何生成 URL。可用的选项有: * * - base_uri: 指定 URL 前部要添加的路径(可以包括协议、域名和端口,以及路径) * - script: 指定 URL 前部要使用的脚本名 * - mode: 指定 URL 生成模式,可以是 standard、pathinfo 和 rewrite * * @param string $udi UDI 字符串 * @param array|string $params 附加参数数组 * @param string $route_name 路由名 * @param array $opts 控制如何生成 URL 的选项 * * @return string 生成的 URL 地址 */ function url($udi, $params = null, $route_name = null, array $opts = null) { static $base_uri; if (is_null($base_uri)) { if (strlen(Q::ini('base_uri')) > 0) { $base_uri = Q::ini('base_uri'); } else { $base_uri = '/' . trim($this->baseDir(), '/'); if ($base_uri != '/') { $base_uri .= '/'; } } } $udi = $this->normalizeUDI($udi); if (!is_array($params)) { $arr = Q::normalize($params, '/'); $params = array(); while ($key = array_shift($arr)) { $value = array_shift($arr); $params[$key] = $value; } } $params = array_filter($params, 'strlen'); // 处理 $opts if (is_array($opts)) { $mode = !empty($opts['mode']) ? $opts['mode'] : self::$_url_mode; $script = !empty($opts['script']) ? $opts['script'] : $this->scriptName(); $url = strlen($opts['base_uri']) > 0 ? rtrim($opts['base_uri'], '/') . '/' : $base_uri; } else { $mode = self::$_url_mode; $url = $base_uri; $script = $this->scriptName(); } if (!is_null($this->_router) && $mode != self::URL_MODE_STANDARD) { // 使用路由生成 URL $params = array_merge($params, $udi); $path = $this->_router->url($params, $route_name); if (self::$_url_mode == self::URL_MODE_PATHINFO && $path != '/') { $url .= $this->scriptName(); } else { $url = rtrim($url, '/'); } $url .= $path; } else { foreach (self::$_udi_defaults as $key => $value) { if ($udi[$key] == $value) { unset($udi[$key]); } unset($params[$key]); } $params = array_filter(array_merge($udi, $params), 'strlen'); $url .= $script; if (!empty($params)) { $url .= '?' . http_build_query($params, '', '&'); } } return $url; }
/** * 构造 url * * url() 方法支持多种调用模式,分别是: * * <ul> * <li>url([控制器名], [动作名], [附加参数数组], [名字空间], [模块名], [路由名])</li> * <li>url(UDI, [附件参数数组], [路由名])</li> * <li>url(参数数组, [路由名])</li> * </ul> * * UDI 是统一目的地标识符(Uniform Destination Identifier)的缩写。 * * UDI 由控制器、动作、名字空间以及模块名组成,采用如下的格式: * * namespace::controller/action@module * * 如果没有提供 namespace 和 module,则 controller 是必须提供的。 * * 可以有下列写法: * * 'controller' * 'controller/action' * '/action' * 'controller@module' * 'controller/action@module' * 'namespace::controller' * 'namespace::controller/action' * 'namespace::controller@module' * 'namespace::controller/action@module' * '@module' * 'namespace::@module' * * @param string $controller_name * @param string $action_name * @param array $params * @param string $namespace * @param string $module * @param string $route_name * * @return string */ function url($controller_name = null, $action_name = null, $params = null, $namespace = null, $module = null, $route_name = null) { static $base_uri; if (is_null($base_uri)) { $base_uri = $this->getProtocol() . '://' . rtrim($_SERVER['SERVER_NAME'], '/'); $server_port = $this->getServerPort(); if ($server_port != 80) { $base_uri .= ":{$server_port}"; } $base_uri .= '/' . ltrim($this->getBaseDir(), '/'); } $controller_accessor = $this->getIni('dispatcher_controller_accessor'); $action_accessor = $this->getIni('dispatcher_action_accessor'); $namespace_accessor = $this->getIni('dispatcher_namespace_accessor'); $module_accessor = $this->getIni('dispatcher_module_accessor'); if (is_array($controller_name)) { // 模式3: url(参数数组, [路由名]) $url_args = $controller_name; $route_name = $action_name; if (isset($url_args['namespace']) || isset($url_args[$namespace_accessor])) { $namespace = isset($url_args['namespace']) ? $url_args['namespace'] : $url_args[$namespace_accessor]; unset($url_args['namespace']); unset($url_args[$namespace_accessor]); } else { $namespace = $this->namespace; } if (isset($url_args['module']) || isset($url_args[$module_accessor])) { $module = isset($url_args['module']) ? $url_args['module'] : $url_args[$module_accessor]; unset($url_args['module']); unset($url_args[$module_accessor]); } else { $module = $this->module; } if (isset($url_args['controller']) || isset($url_args[$controller_accessor])) { $controller_name = isset($url_args['controller']) ? $url_args['controller'] : $url_args[$controller_accessor]; unset($url_args['controller']); unset($url_args[$controller_accessor]); } else { $controller_name = $this->controller_name; } if (isset($url_args['action']) || isset($url_args[$action_accessor])) { $action_name = isset($url_args['action']) ? $url_args['action'] : $url_args[$action_accessor]; unset($url_args['action']); unset($url_args[$action_accessor]); } else { $action_name = null; } $params = $url_args; } else { $destinfo = $this->destinfo($controller_name); if (is_array($action_name)) { // 模式2: url(UDI, [附件参数数组], [路由名]) $module = $destinfo[self::DESTINFO_MODULE]; $namespace = $destinfo[self::DESTINFO_NAMESPACE]; $controller_name = $destinfo[self::DESTINFO_CONTROLLER]; $route_name = $params; $params = $action_name; $action_name = $destinfo[self::DESTINFO_ACTION]; } else { // 模式1: url([控制器名], [动作名], [附加参数数组], [名字空间], [模块名], [路由名]) if (is_null($module)) { $module = $destinfo[self::DESTINFO_MODULE]; } if (is_null($namespace)) { $namespace = $destinfo[self::DESTINFO_NAMESPACE]; } $controller_name = $destinfo[self::DESTINFO_CONTROLLER]; if (is_null($action_name)) { $action_name = $destinfo[self::DESTINFO_ACTION]; } } } // 确定控制器和动作的名字 $controller_name = empty($controller_name) ? $this->getIni('dispatcher_default_controller') : $controller_name; $action_name = empty($action_name) ? $this->getIni('dispatcher_default_action') : $action_name; $controller_name = strtolower($controller_name); $action_name = strtolower($action_name); $url_args = array(); if (!is_null($this->_router)) { $module_accessor = 'module'; $namespace_accessor = 'namespace'; $controller_accessor = 'controller'; $action_accessor = 'action'; } if ($module) { $url_args[$module_accessor] = $module; } if ($namespace) { $url_args[$namespace_accessor] = $namespace; } $url_args[$controller_accessor] = $controller_name; $url_args[$action_accessor] = $action_name; if (is_array($params) && !empty($params)) { $url_args = array_merge($url_args, $params); } if (!is_null($this->_router)) { $url = rtrim($base_uri, '/'); if (self::$_url_mode == self::URL_MODE_PATHINFO) { $url .= '/' . $this->getScriptName(); } $url .= $this->_router->url($url_args, $route_name); } else { $url = rtrim($base_uri, '/') . '/' . $this->getScriptName() . '?' . http_build_query($url_args, '', '&'); } return $url; }
/** * 构造 url * * 用法: * * @code php * url(UDI, [附加参数数组], [路由名]) * @endcode * * UDI 是统一目的地标识符(Uniform Destination Identifier)的缩写。 * UDI 由控制器、动作、名字空间以及模块名组成,采用如下的格式: * * @code php * namespace::controller/action@module * @endcode * * UDI 字符串中,每一个部分都是可选的。 * 如果没有提供控制器和动作名,则使用当前的控制器和默认动作名(index)代替。 * 同样,如果未提供模块名和名字空间,均使用当前值代替。 * * UDI 字符串写法示例: * * @code php * 'controller' * 'controller/action' * '/action' * 'controller@module' * 'controller/action@module' * 'namespace::controller' * 'namespace::controller/action' * 'namespace::controller@module' * 'namespace::controller/action@module' * '@module' * 'namespace::@module' * @endcode * * 示例: * @code php * url('admin::posts/edit', array('id' => $post->id())); * @endcode * * 在使用 PATHINFO 和 URL 重写时,可以使用通过制定路由名来强制要求 QeePHP * 采用指定的路由规则来生成 URL。强制指定路由规则可以加快 URL 的生成, * 但在路由规则名称发生变化时,需要修改生成 URL 的代码。 * * @param string $udi UDI 字符串 * @param array $params 附加参数数组 * @param string $route_name 路由名 * * @return string 生成的 URL 地址 */ function url($udi, array $params = null, $route_name = null) { static $base_uri; if (is_null($base_uri)) { $base_uri = $this->protocol() . '://' . rtrim($_SERVER['SERVER_NAME'], '/'); $server_port = $this->serverPort(); if ($server_port != 80) { $base_uri .= ":{$server_port}"; } $base_uri .= '/' . ltrim($this->baseDir(), '/'); } $udi = $this->normalizeUDI($udi); if (!is_array($params)) { $params = array(); } if (!is_null($this->_router)) { // 使用路由生成 URL $url = rtrim($base_uri, '/'); if (self::$_url_mode == self::URL_MODE_PATHINFO) { $url .= '/' . $this->scriptName(); } $params = array_merge($params, $udi); $url .= $this->_router->url($params, $route_name); } else { foreach (self::$_udi_defaults as $key => $value) { if ($udi[$key] == $value) { unset($udi[$key]); } unset($params[$key]); } $params = array_filter(array_merge($udi, $params)); $url = rtrim($base_uri, '/') . '/' . $this->scriptName() . '?'; $url .= http_build_query($params, '', '&'); } return $url; }