lovelvaly 发表于 2010-1-8 11:43:28

CI中实现两种风格路由

在支持url path_info 以及 url_rewrite 的环境中.CI 可以生成非常友好的url .
但是如果某个环境不支持path_info 以及 url_rewrite ,如何让CI 自动生成传统的url ,形如:
http://localhost/codeigniter172/index.php?c=blog&m=nodes&per_page=6

步骤:
(1) application/config/config.php中

$config['uri_protocol']        = "AUTO";
$config['enable_query_strings'] = TRUE; // 默认值为false.此刻我们开启.为了让它生成传统的url.
//新增一项.应用程序入口,单一入口程序常用的做法.
$config['app_entrance'] = "index.php";


(2).重载site_url()
新建 application/libraries/MY_Config.php

<?php
class MY_Config extends CI_Config
{
        function site_url($uri)
        {
                if(!$this->item('enable_query_strings')){
                        return parent::site_url($uri);
                }
                else{
                        $class_key = $this->item('controller_trigger');
                        $func_key = $this->item('function_trigger');
                        if (!$uri)
                        {
                                return $this->slash_item('base_url');
                        }
                        else
                        {
                                $app_entrance = ($this->item('app_entrance'))? $this->item('app_entrance') : "index.php" ;
                                $last = '';
                                $uri = trim($uri,'/');
                                $arr = explode('/',$uri);
                                $func = (isset($arr))? '&'.$func_key.'='.$arr:'';
                                if(count($arr)>2){
                                        $arr_parms = array();
                                        $arr_last = array_slice($arr,2);
                                        $i = 1;
                                        foreach ($arr_last as $v){
                                                $arr_parms[] = 'parms'.$i++.'='.$v;
                                        }
                                        $last ='&'.implode("&",$arr_parms);
                                }
                                $uri = "$app_entrance?$class_key={$arr}$func";
                                return $this->slash_item('base_url').$uri.$last;
                        }
                }
        }
}
?>


(3)
重载_explode_segments()
是为了采用统一的方式获取 get 变量 .如 从该 url : http://localhost/codeigniter172/index.php?c=blog&m=nodes&per_page=6
$this->uri->segements(3) 即获取 $_GET['per_page'] 的值 .
新建 application/libraries/MY_URI.php

<?php
class MY_URI extends CI_URI
{
        function _explode_segments()
        {
                if(!$this->config->item('enable_query_strings')){
                        parent::_explode_segments();
                }
                else
                {
                        if(empty($_SERVER['QUERY_STRING'])){
                                show_error('Current Url error',500);
                        }
                        $this->segments = 'NOUSE';
                        $i = 0;
                        $arr_parms = explode('&',$_SERVER['QUERY_STRING']);
                        foreach ($arr_parms as $v){
                                $arr_v = explode('=',$v);
                                $this->segments[++$i] = $arr_v;
                        }
                }
        }
}
?>


(4) 重载 _set_routing()
目的是为了采用传统url 处理 MVC时,能够执行 _explode_segments()
新增 application/libraries/MY_Router.php

<?php
class MY_Router extends CI_Router
{
        function _set_routing()
        {
                // Are query strings enabled in the config file?
                // If so, we're done since segment based URIs are not used with query strings.
                if ($this->config->item('enable_query_strings') === TRUE AND isset($_GET[$this->config->item('controller_trigger')]))
                {
                        $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));

                        if (isset($_GET[$this->config->item('function_trigger')]))
                        {
                                $this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
                        }
                        //must process the url into segmets array.so we can use an uniform method to get .
                                                //仅仅新增了下面这一行.               
                                        $this->uri->_explode_segments();
                        return;
                }
               
                // Load the routes.php file.
                @include(APPPATH.'config/routes'.EXT);
                $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
                unset($route);

                // Set the default controller so we can display it in the event
                // the URI doesn't correlated to a valid controller.
                $this->default_controller = ( ! isset($this->routes['default_controller']) OR $this->routes['default_controller'] == '') ? FALSE : strtolower($this->routes['default_controller']);       
               
                // Fetch the complete URI string
                $this->uri->_fetch_uri_string();
       
                // Is there a URI string? If not, the default controller specified in the "routes" file will be shown.
                if ($this->uri->uri_string == '')
                {
                        if ($this->default_controller === FALSE)
                        {
                                show_error("Unable to determine what should be displayed. A default route has not been specified in the routing file.");
                        }
                       
                        if (strpos($this->default_controller, '/') !== FALSE)
                        {
                                $x = explode('/', $this->default_controller);

                                $this->set_class(end($x));
                                $this->set_method('index');
                                $this->_set_request($x);
                        }
                        else
                        {
                                $this->set_class($this->default_controller);
                                $this->set_method('index');
                                $this->_set_request(array($this->default_controller, 'index'));
                        }

                        // re-index the routed segments array so it starts with 1 rather than 0
                        $this->uri->_reindex_segments();
                        log_message('debug', "No URI present. Default controller set.");
                        return;
                }
                unset($this->routes['default_controller']);
               
                // Do we need to remove the URL suffix?
                $this->uri->_remove_url_suffix();
               
                // Compile the segments into an array
                $this->uri->_explode_segments();
                // Parse any custom routing that may exist
                $this->_parse_routes();               
                // Re-index the segment array so that it starts with 1 rather than 0
                $this->uri->_reindex_segments();
        }
}
?>


完成上述步骤后,如果你想采用传统url (不是搜索引擎友好的url) 访问,只需要将 $config['enable_query_strings'] = TRUE;
这时: siet_url('blog/edit/15') 生成的url 即为: http://localhost/codeigniter172/index.php?c=blog&m=edit&params1=15;
如果把 $config['enable_query_strings'] = false;
site_url('blog/edit/15') 生成的url 即为: http://localhost/codeigniter172/blog/edit/15

因此,你在开发过程中所有生成url 的地方,都应采用 site_url() 这个函数去完成. 部署到server 时,如果server 不支持 path_info 或者 url_rewrite. 无需大量改动
只需改一个配置参数即可.

lovelvaly 发表于 2010-1-8 16:29:31

基于以上思想,发现CI_Calendar 类中有些问题.
CI_Calendar 的 generate 方法 中对"上一月", "下一月"的link url 处理,应该算是一个bug,我觉得.CI 的下一个版本应该修正这个bug.
因为CI_Pagenation 类中 是有作类似的处理的.

if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
                {
                        $this->base_url = rtrim($this->base_url).'&amp;'.$this->query_string_segment.'=';
                }
                else
                {
                        $this->base_url = rtrim($this->base_url, '/') .'/';
                }

(第 160 行 往下看)
        //this is a bug---should be fixed.
                        //$out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_previous_cell']);
                        if ($this->CI->config->item('enable_query_strings') === TRUE )
                        {
                                $out .= str_replace('{previous_url}', $this->next_prev_url.'&amp;params1='.$adjusted_date['year'].'&amp;params2='.$adjusted_date['month'], $this->temp['heading_previous_cell']);
                        }
                        else
                                $out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_previous_cell']);
.....
// "next" month link
                if ($this->show_next_prev == TRUE)
                {               
                        $adjusted_date = $this->adjust_date($month + 1, $year);
                        if ($this->CI->config->item('enable_query_strings') === TRUE )
                                $out .= str_replace('{next_url}', $this->next_prev_url.'&amp;params1='.$adjusted_date['year'].'&amp;params2='.$adjusted_date['month'], $this->temp['heading_next_cell']);
                        else
                                $out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->temp['heading_next_cell']);
                }

bpzc 发表于 2010-1-11 02:49:06

很有用~~~
页: [1]
查看完整版本: CI中实现两种风格路由