/** * 测试反向解析 */ 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)); } }
/** * 渲染指定的视图文件 * * 渲染时,视图要使用的数据保存在控件的 $view 属性中。 * * @param string $viewname * @param boolean $return * * @return string */ protected function _renderBlock($viewname, $return = false) { if (!is_object($this->_view_adapter)) { $adapter_class = is_null($this->_view_adapter_class) ? $this->context->getIni('view_adapter') : $this->_view_adapter_class; $adapter_obj_id = "webcontrols_{$adapter_class}"; if (Q::isRegistered($adapter_obj_id)) { /** * @var QView_Adapter_Abstract */ $adapter = Q::registry($adapter_obj_id); } else { /** * @var QView_Adapter_Abstract */ $adapter = new $adapter_class($this->context); Q::register($adapter, $adapter_obj_id); } } else { $adapter = $this->_view_adapter; } $adapter->clear(); $adapter->assign($this->view); $adapter->assign('_ctx', $this->context); $filename = QView::getControlViewFilename($this->context, $adapter, $viewname, $this->_controls_view_dir); if ($return) { return $adapter->fetch($filename); } else { return $adapter->display($filename); } }
/** * 实例化一个控件 * * @param QContext $context * @param string $type * @param string $id * @param array $attribs * * @return QUI_Control_Abstract */ static function control($context, $type, $id = null, array $attribs = null) { static $standard_loaded = false; if (empty($id)) { $id = strtolower($type); } else { $id = strtolower($id); } $class_name = 'Control_' . ucfirst(strtolower($type)); if (!$standard_loaded) { $standard_loaded = true; require_once Q_DIR . '/qui/control/_standard.php'; } if (!is_array($attribs)) { $attribs = array(); } if (is_null($context)) { $context = QContext::instance(); } $control = new $class_name($context, $id, $attribs); /* @var $control QUI_Control_Abstract */ $control->namespace = $context->namespace; $control->module = $context->module; return $control; }
/** * 根据运行时上下文对象,调用相应的控制器动作方法 * * @param array $args * * @return mixed */ function run(array $args = array()) { $context = QContext::instance(); $udi = $context->requestUDI('array'); $dir = dirname(__FILE__) . '/app/controller'; $class_name = 'controller_'; $controller_name = strtolower($udi[QContext::UDI_CONTROLLER]); $class_name .= $controller_name; $filename = "{$controller_name}_controller.php"; // 载入控制器文件 if (!class_exists($class_name, false)) { Q::loadClassFile($filename, array($dir), $class_name); } // 构造控制器对象 $controller = new $class_name($this); $action_name = $udi[QContext::UDI_ACTION]; $response = $controller->execute($action_name, $args); if (is_object($response) && method_exists($response, 'execute')) { // 如果返回结果是一个对象,并且该对象有 execute() 方法,则调用 $response = $response->execute(); } elseif ($response instanceof QController_Forward) { // 如果是一个 QController_Forward 对象,则将请求进行转发 $response = $this->run($response->args); } // 其他情况则返回执行结果 return $response; }
/** * 执行指定的动作 * * @return mixed */ function execute($action_name, array $args = array()) { $action_method = "action{$action_name}"; // 执行指定的动作方法 $this->_before_execute(); #IFDEF DBEUG QLog::log('EXECUTE ACTION: ' . get_class($this) . '::' . $action_method . '()', QLog::DEBUG); #ENDIF $this->_view['_MSG'] = $this->_app->getFlashMessage(); Q::replaceIni('OrderAvailable', true); Q::replaceIni('isAdmin', false); #dump(Q::ini('appini/managers')); if ($this->_user) { if (in_array($this->_user->user_mail, Q::ini('appini/managers'))) { Q::replaceIni('isAdmin', true); } } $this->_view['_UDI'] = QContext::instance()->requestUDI(false); $response = call_user_func_array(array($this, $action_method), $args); $this->_after_execute($response); if (is_null($response) && is_array($this->_view)) { // 如果动作没有返回值,并且 $this->view 不为 null, // 则假定动作要通过 $this->view 输出数据 $config = array('view_dir' => $this->_getViewDir()); $response = new $this->_view_class($config); $response->setViewname($this->_getViewName())->assign($this->_view); #dump($response); $this->_before_render($response); } elseif ($response instanceof $this->_view_class) { $response->assign($this->_view); $this->_before_render($response); } #dump($response); return $response; }
/** * 输出一个元素 */ function element($element) { $dir = QView::getExtraViewDir($this->context, '_elements', 'elements_view_dir'); $filename = "{$element}_element{$this->tpl_file_ext}"; if ($this->context->getIni('view_config/flat_dir') > 0) { $filename = '_' . $filename; } $_ctx = $this->context; include "{$dir}/{$filename}"; }
/** * 构造函数 * * @param QContext $context * @param array $args */ function __construct($destination, QContext $context, array $args = array()) { /** * $destination 由三部分组成: * * namespace::controller/action@module * * 如果没有提供 namespace 和 module,则 controller 是必须提供的。 * * 可以有下列写法: * * '/action' * 'controller' * 'controller/action' * 'controller@module' * 'controller/action@module' * 'namespace::controller' * 'namespace::controller/action' * 'namespace::controller@module' * 'namespace::controller/action@module' * '@module' * 'namespace::@module' */ if (strpos($destination, '::') !== false) { $arr = explode('::', $destination); $namespace = array_shift($arr); $destination = array_shift($arr); } if (strpos($destination, '@') !== false) { $arr = explode('@', $destination); $module = array_pop($arr); $destination = array_pop($arr); if (!isset($namespace)) { $namespace = ''; } } $arr = explode('/', $destination); $controller = array_shift($arr); if (empty($controller)) { $controller = $context->controller_name; } $action = array_shift($arr); $context = QContext::instance(); if (isset($module)) { $context->module_name = $module; } if (isset($namespace)) { $context->namespace = $namespace; } $context->controller_name = $controller; $context->action_name = $action; $context->setRequestUDI(); $this->context = $context; $this->args = $args; }
/** * 执行指定的 Action 方法 * * @param QContext $context * @param array $args * * @return mixed */ protected function _executeAction(QContext $context, array $args = array()) { // 检查是否有权限访问 $controller_name = $context->controller_name; $action_name = $context->action_name; $namespace = $context->namespace; $module = $context->module_name; QLog::log(sprintf('Execute controller action: "%s".', $context->getRequestUDI())); if (!$this->checkAuthorized($controller_name, $action_name, $namespace, $module)) { $response = call_user_func($context->getIni('dispatcher_on_access_denied'), $context); } else { // 尝试载入控制器 $class_name = $context->getIni('controller_class_prefix') . 'Controller_'; if ($namespace) { $class_name .= ucfirst($namespace) . '_'; } $class_name .= ucfirst(str_replace('_', '', $controller_name)); $app_config = self::getAppConfig($this->_appid); if ($module) { $dir = $app_config['ROOT_DIR'] . "/modules/{$module}/controller"; } else { $dir = $app_config['ROOT_DIR'] . "/app/controller"; } if ($namespace) { $dir .= DS . $namespace; } // 构造控制器对象 try { $filename = $controller_name . '_controller.php'; Q::loadClassFile($filename, array($dir), $class_name); } catch (QException $ex) { $response = call_user_func($this->context->getIni('dispatcher_on_action_not_found'), $context); if (is_null($response)) { $response = ''; } } if (!isset($response)) { $controller = new $class_name($this, $context); /* @var $controller QController_Abstract */ if ($context->isAJAX()) { $controller->view = null; } $response = $controller->_execute($args); } } if (is_object($response) && method_exists($response, 'execute')) { $response = $response->execute(); } elseif ($response instanceof QController_Forward) { // 更新 flash message $key = $this->context->getIni('app_flash_message_key'); unset($_SESSION[$key]); $response = $this->_executeAction($response->context, $response->args); } return $response; }
function getCurrentSubMenu(array $menu) { $context = QContext::instance(); $controller = $context->controller_name; $action = $context->action_name; foreach ($menu as $item) { if ($item['controller'] == $controller && $item['action'] == $action) { return $item; } } return null; }
/** * 测试反向解析 */ 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($test, "Expected route name is [{$offset}] : {$path}. actual is {$router->lastReverseMatchedRouteName()}."); } $this->assertEquals($route_name, $router->lastReverseMatchedRouteName(), "Expected route name is [{$route_name}]."); $this->assertEquals($path, $result, print_r($copy, true) . "\n" . print_r($test, true)); } }
/** * 渲染指定的视图文件 * * 渲染时,视图要使用的数据保存在控件的 $_view 属性中。 * * @param string $filename * @param array $more_vars * * @return string */ protected function _fetchView($filename, array $more_vars = null) { $vars = $this->_view; $vars['_ctx'] = $this->_context; $vars['_CTL_ID'] = $this->id(); $vars['_BASE_DIR'] = $this->_context->baseDir(); $vars['_BASE_URI'] = $this->_context->baseUri(); $vars['_REQUEST_URI'] = $this->_context->requestUri(); if (is_array($more_vars)) { $vars = array_merge($vars, $more_vars); } //if (is_null($this->_render)) //{ $this->_render = new $this->_render_class(dirname($filename)); //} $this->_render->vars($vars); $extname = pathinfo($filename, PATHINFO_EXTENSION); $pextname = $this->_render->extname(); if (empty($extname) || $extname != $pextname && !empty($pextname)) { $filename .= '.' . ($pextname ? $pextname : 'php'); } return $this->_render->parse($filename); }
/** * 渲染指定的视图文件 * * 渲染时,视图要使用的数据保存在控件的 $_view 属性中。 * * @param string $filename * @param array $more_vars * * @return string */ protected function _fetchView($filename, array $more_vars = null) { $vars = $this->_view; /** * TODO! 全局变量应该放到 控件抽象类 _before_render() 中 */ $vars['_ctx'] = $this->_context; $vars['_CTL_ID'] = $this->id(); $vars['_BASE_DIR'] = $this->_context->baseDir(); $vars['_BASE_URI'] = $this->_context->baseUri(); $vars['_REQUEST_URI'] = $this->_context->requestUri(); // if (is_array($more_vars)) { $vars = array_merge($vars, $more_vars); } if (strpos($filename, 'view:') === 0) { $filename = Q::ini('app_config/APP_DIR') . DS . 'view' . DS . ltrim(substr($filename, 5), '/\\'); } elseif ($filename[0] != DS && strpos($filename, ':') === false) { $_class_name = strtolower(get_class($this)); $_sep = explode('_', $_class_name); array_pop($_sep); $filename = Q::ini('app_config/APP_DIR') . DS . implode($_sep, DS) . DS . ltrim($filename, '/\\'); } if (is_null($this->_render)) { $this->_render = new $this->_render_class(dirname($filename)); } else { // TODO! 假如共享视图解析器实例,需在此做必要处理 } $this->_render->assign($vars); $extname = pathinfo($filename, PATHINFO_EXTENSION); $pextname = $this->_render->extname(); if (empty($extname) || $extname != $pextname && !empty($pextname)) { $filename .= '.' . ($pextname ? $pextname : 'php'); } return $this->_render->parse($filename); }
/** * 视图调用未定义的控制器或动作时的错误处理函数 */ protected function _on_action_not_defined() { if (isset($_GET['sike'])) { dump(QContext::instance()->requestUDI('array')); } else { header('HTTP/1.1 403 Forbidden'); return false; } }
/** * 返回请求 URL 中的基础路径(不包含脚本名称) * * 几个示例: * * <ul> * <li>请求 http://www.example.com/index.php?controller=posts&action=create</li> * <li>返回 /</li> * </ul> * <ul> * <li>请求 http://www.example.com/news/index.php?controller=posts&action=create</li> * <li>返回 /news/</li> * </ul> * <ul> * <li>请求 http://www.example.com/index.php/posts/create</li> * <li>返回 /</li> * </ul> * <ul> * <li>请求 http://www.example.com/news/show/id/1</li> * <li>返回 /</li> * </ul> * * @return string 请求 URL 中的基础路径 */ function baseDir() { if (self::$_base_dir) { return self::$_base_dir; } $base_uri = $this->baseUri(); if (substr($base_uri, -1, 1) == '/') { $base_dir = $base_uri; } else { $base_dir = dirname($base_uri); } self::$_base_dir = rtrim($base_dir, '/\\') . '/'; return self::$_base_dir; }
function setUp() { $this->_ctx = QContext::instance(); }
/** * 构造函数 * * @param string|array $udi * @param array $args */ function __construct($udi, array $args = array()) { QContext::instance()->changeRequestUDI($udi); $this->args = $args; }
/** * 清除所有模板变量 * * @return QView_Render_PHP */ function cleanVars() { ///* $context = QContext::instance(); $this->_vars = array('_ctx' => $context, '_BASE_DIR' => $context->baseDir(), '_BASE_URI' => $context->baseUri(), '_REQUEST_URI' => $context->requestUri()); //*/ // TODO! 全局变量应该放到 控制器抽象类 _before_render() 中 //$this->_vars = array(); return $this; }
/** * QContext::url() 方法的简写,用于构造一个 URL 地址 * * url() 方法的参数比较复杂,请参考 QContext::url() 方法的详细说明。 * * @param string $controller_name * @param string|array $action_name * @param array $params * @param string $namespace * @param string $module_name * @param string $route_name * * @return string */ function url($controller_name = null, $action_name = null, $params = null, $namespace = null, $module_name = null, $route_name = null) { return QContext::instance()->url($controller_name, $action_name, $params, $namespace, $module_name, $route_name); }
/** * 构造限於当前控制器的 URL * * @param string $action * @param array $params * * @return string */ protected function _url($action = null, array $params = null) { return $this->context->url($this->context->controller_name, $action, $params); }
/** * 根据 php.ini 中的 magic quotes gpc 设置去除超全局变量中自动添加的转义符 */ private function _initOneTime() { if (self::$_root) { return; } self::$_root = $this; // 禁止 magic quotes set_magic_quotes_runtime(0); // 处理被 magic quotes 自动转义过的数据 if (get_magic_quotes_gpc()) { $in = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST); while (list($k, $v) = each($in)) { foreach ($v as $key => $val) { if (!is_array($val)) { $in[$k][$key] = stripslashes($val); continue; } $in[] =& $in[$k][$key]; } } unset($in); } $url_mode = strtolower($this->getIni('dispatcher_url_mode')); if ($url_mode == self::URL_MODE_PATHINFO || $url_mode == self::URL_MODE_REWRITE) { $this->_router = new QRouter($this); $result = $this->_router->match($this->getPathinfo()); if ($result) { foreach ($result as $var => $value) { if (empty($_GET[$var])) { $_GET[$var] = $_REQUEST[$var] = $value; } } } self::$_url_mode = $url_mode; } else { self::$_url_mode = self::URL_MODE_STANDARD; $this->_router = null; } }
/** * 载入指定类的定义文件,如果载入失败抛出异常 * * @code * Q::loadClass('Table_Posts'); * @endcode * * 在查找类定义文件时,类名称中的“_”(下划线)会被替换为目录分隔符,从而确定类定义文件的存储路径。 * * 为了能够适应复杂应用程序的需求,Q::loadClass() 会按照两种方式在特定的目录中查找类定义文件。 * * <ul> * <li> * 如果没有提供 $dirs 参数,Q::loadClass() 会按照 QeePHP 内部的一个“类载入路径”来查找指定类的定义文件; * * “类载入路径”是 QeePHP 内部的一个目录列表,确定了 Q::loadClass() 会自动到哪些目录中去查找类定义文件。 * 当 Q::loadClass() 查找类定义文件时,首先将类名称中的“_”(下划线)替换为目录分隔符, * 然后按照“类载入路径”一个个目录的去查找类定义文件。 * * <ul> * <li>假设当前的“类载入路径”为 /www/mysite/app 和 /www/mysite/lib/qeephp;</li> * <li>要载入 QDB_ActiveRecord_Meta 类;</li> * <li>Q::loadClass() 首先从 QDB_ActiveRecord_Meta 类名称获得定义文件的存储路径为 qdb/activerecord/meta.php;</li> * <li>Q::loadClass() 接下来会尝试读取 /www/mysite/app/qdb/activerecord/meta.php 和 * /www/mysite/lib/qeephpqdb/activerecord/meta.php 文件。</li> * </ul> * * 从这个搜索过程可以看出,“类搜索路径”确定了类定义文件所在的父级目录,而类定义文件的确切存储位置是根据 * “类搜索路径”和类名称来确定的。可以使用 Q::import() 方法来添加更多的目录到 QeePHP 内部的“类搜索路径”中。 * </li> * * <li>如果提供了 $dirs 参数,则忽略 QeePHP 内部的“类搜索路径”,而是按照 $dirs 参数指定的“搜索路径”来查找类定义文件。</li> * </ul> * * $dirs 参数可以是一个以 PATH_SEPARATOR 常量分隔的字符串,也可以是一个包含多个目录名的数组。 * * @code * Q::loadClass('Table_Posts', array('/www/mysite/app', '/www/mysite/lib')); * @endcode * * 如果要载入特定模块的一个类,可以在类名称后面添加 "@模块名" 来指定,例如: * * @code * // 载入 CMS 模块的 Post 类 * Q::loadClass('Post@cms'); * @endcode * * 模块名是不区分大小写的,但建议使用全小写的模块名。 * * @param string $className * 要载入的类 * @param string|array $dirs * 指定载入类的搜索路径 */ static final function loadClass($class_name, $dirs = null) { if (class_exists($class_name, false) || interface_exists($class_name, false)) { return; } $class_name = strtolower($class_name); if (strpos($class_name, '@') !== false) { list($class_name, $module_name) = explode('@', $class_name); QContext::instance($module_name); } $filename = str_replace('_', DS, $class_name); if ($filename != $class_name) { $dirname = dirname($filename); if (!empty($dirs)) { if (!is_array($dirs)) { if (empty($dirs)) { $dirs = array(); } else { $dirs = explode(PATH_SEPARATOR, $dirs); } } foreach ($dirs as $offset => $dir) { $dirs[$offset] = $dir . DS . $dirname; } } else { $dirs = array(); foreach (self::$_class_path as $dir) { if ($dir == '.') { $dirs[] = $dirname; } else { $dir = rtrim($dir, '\\/'); $dirs[] = $dir . DS . $dirname; } } } $filename = basename($filename) . '.php'; } else { $dirs = self::$_class_path; $filename .= '.php'; } self::loadClassFile($filename, $dirs, $class_name); }
/** * 获得指定控制器的 ACL * * @param string|array $udi * * @return array */ function controllerACL($udi) { if (!is_array($udi)) { $udi = QContext::instance()->normalizeUDI($udi); } $path = 'acl_global'; if ($udi[QContext::UDI_MODULE] && $udi[QContext::UDI_MODULE] != QContext::UDI_DEFAULT_MODULE) { $path .= '/' . $udi[QContext::UDI_MODULE]; } if ($udi[QContext::UDI_NAMESPACE] && $udi[QContext::UDI_NAMESPACE] != QContext::UDI_DEFAULT_NAMESPACE) { $path .= '/' . $udi[QContext::UDI_NAMESPACE]; } $acl = Q::ini($path); if (!is_array($acl)) { return Q::ini('acl_default'); } $acl = array_change_key_case($acl, CASE_LOWER); if (isset($acl[$udi[QContext::UDI_CONTROLLER]])) { return (array) $acl[$udi[QContext::UDI_CONTROLLER]]; } return isset($acl[QACL::ALL_CONTROLLERS]) ? (array) $acl[QACL::ALL_CONTROLLERS] : Q::ini('acl_default'); }
function __url($udi = null, $arg = array()) { if (is_array($udi)) { $arg = $udi; $udi = null; } $context = QContext::instance(); $get = $_GET; unset($get['module']); unset($get['action']); unset($get['controller']); if ($udi === false) { $arg = $arg ? $arg : $get; } else { $arg = $arg ? array_merge($get, $arg) : $get; } $udi = $udi ? $udi : $context->requestUDI(false); return url($udi) . '?' . http_build_query($arg, '', '&'); }
/** * 构造函数 * * @param QContext $context */ function __construct(QContext $context) { $this->context = $context; $this->_rules = (array) $context->getIni('routes'); //$this->_log = new QLog(array('log_writer_filename' => 'router.log')); }
/** * 辅助方法,用于获得一些特定目录的路径 * * @return string */ static function getExtraViewDir(QContext $context, $suffix, $ini_name, $ini_default = null) { if ($ini_default) { return $ini_default; } $dir = $context->getIni('view_config/' . $ini_name); if ($dir) { return $dir; } $dir = self::getViewDir($context, $ini_default); if (intval($context->getIni('view_config/flat_dir')) < 1) { $dir = $dir . '/' . $suffix; } return $dir; }
/** * 构造函数 */ function __construct() { $this->_context = QContext::instance(); }
/** * 构造函数 * * @param string|array $udi * @param array $args */ function __construct($udi, array $args = array()) { #$_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest'; QContext::instance()->changeRequestUDI($udi); $this->args = array_replace($args, array('forward' => true)); }
/** * QContext::url() 方法的简写,用于构造一个 URL 地址 * * url() 方法的参数比较复杂,请参考 QContext::url() 方法的详细说明。 * * @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) { return QContext::instance()->url($udi, $params, $route_name, $opts); }
protected function __construct() { $arr = Helper_Yaml::load(QContext::instance()->ROOT_DIR() . '/config/menu.yaml'); $this->_all = $this->_prepareMenus($arr); }
/** * 清除所有模板变量 * * @return QView_Render_PHP */ function cleanVars() { $context = QContext::instance(); $this->_vars = array('_ctx' => $context, '_BASE_DIR' => $context->baseDir(), '_BASE_URI' => $context->baseUri(), '_REQUEST_URI' => $context->requestUri()); return $this; }