【问题标题】:Codeigniter Dynamic RoutingCodeigniter 动态路由
【发布时间】:2011-08-07 18:19:07
【问题描述】:

你好,我不会做那样的东西。

http://example.com/ - 主控制器

http://example.com/rules/ - 从数据库获取内容的主控制器,但如果不存在 返回 404 页面。 (没关系,没问题。)

但如果我在 application/controlles/rules/ 中有子文件夹 我想将它重定向到规则文件夹中的主控制器。

以下代码可以解决问题,但我不知道它是如何正确实现的。 在routes.php:

$route['default_controller'] = "main";
$route['404_override'] = '';

$dirtest = $route['(:any)'];

if (is_dir(APPPATH.'controllers/'.$dirtest)) {
$route['(:any)'] = $dirtest.'/$1';
} else {
$route['(:any)'] = 'main/index/$1';
}

好的,我有什么:

控制器/main.php

class Main extends CI_Controller {

    public function __construct()
        {
            parent::__construct();
            $this->load->model('main_model');
        }

    public function index($method = null)
    {
        if (is_dir(APPPATH.'controllers/'.$method)) {
            // Need re-rout to the application/controllers/$method/
        } else {
            if ($query = $this->main_model->get_content($method)) {
                $data['content'] = $query[0]->text;
                // it shows at views/main.php
            } else {
                show_404($method);
            }
        }
        $data['main_content'] = 'main';
        $this->load->view('includes/template', $data);
    }

}

再次更新(routes.php): 所以,看起来就像我搜索的内容(工作示例):

$route['default_controller'] = "main";
$route['404_override'] = '';


$subfolders = glob(APPPATH.'controllers/*', GLOB_ONLYDIR);

foreach ($subfolders as $folder) {
    $folder = preg_replace('/application\/controllers\//', '', $folder);
    $route[$folder] = $folder.'/main/index/';
    $route[$folder.'/(:any)'] = $folder.'/main/$1';
}

$route['(:any)'] = 'main/index/$1';

但是,完全需要这样的东西:

http://example.com/1/2/3/4/5/6/...

  1. 文件夹“controllers”有子文件夹“1”?
  2. 是:文件夹“1”有子文件夹“2”?
  3. 否:文件夹“1”有控制器“2.php”?
  4. 否:控制器“controllers/1/main.php”有函数“2”?
  5. 是:重定向到 http://example.com/1/2/ - 其中 3,4,5 - 参数..

真的很好,当你有这样的结构时:

http://example.com/blog/ - recent blog's posts
http://example.com/blog/2007/ - recent from 2007 year blog's posts
http://example.com/blog/2007/06/ - same with month number
http://example.com/blog/2007/06/29/ - same with day number
http://example.com/blog/web-design/ - recent blog's post's about web design
http://example.com/blog/web-design/2007/ - blog' posts about web design from 2007 years.
http://example.com/blog/current-post-title/ - current post

我发现http://codeigniter.com/forums/viewthread/97024/#490613也很有趣

【问题讨论】:

  • 你能发布一个你正在尝试做的重新路由的例子吗?
  • Olezaika:我觉得codeigniter docs about routing 挺好的。
  • 不,你不明白我想要什么。用两个词我需要:如果我在controllres 创建一些像“new_folder”这样的文件夹,那么在routes.php 中追加字符串“$route['new_folder/(:any)'] = 'new_folder/$1'"
  • @Olezaika:我已经添加了一个答案,我知道文档没有涵盖您的具体情况,它只是为了提供一些帮助。
  • 不过,谢谢,但我以前读过。

标签: php codeigniter codeigniter-url


【解决方案1】:

我没有仔细阅读您的问题,但这立即引起了我的注意:

if (is_dir($path . '/' . $folder)) {
    echo "$route['$folder/(:any)'] = '$folder/index/$1';"; //<---- why echo ???
}

老实说,我不确定为什么除了无法正常工作之外,这并没有给您带来严重的问题。

你不想echo这里的路由,那只会尝试将字符串打印到屏幕上,它甚至不会被解释为PHP。引号也有一些问题需要纠正,以便可以将变量读取为变量,而不是字符串。试试这个:

if (is_dir($path . '/' . $folder)) {
    $route[$folder.'/(:any)'] = $folder.'/index/$1';
}

旁白:我想提供一些与您的问题没有直接的额外资源,但应该可以帮助您找到解决方案:

【讨论】:

  • 是的,谢谢,这正是我所需要的。其他感谢 glob() 函数。
  • 如果您只需要 目录,只需使用 glob(APPPATH.'controllers/*', GLOB_ONLYDIR)。我认为有一种更简单的方法可以在没有目录扫描的情况下完成所有这些操作,但我不能 100% 确定您要的是什么。
  • 太棒了!使用 globe() 更新帖子;
【解决方案2】:

很难说您的路线注册失败的原因。从您的代码中,我可以看到您没有注册路由(您只是回显它们),另外我看到字符串中变量的使用不一致。可能你有点混淆了,关于路由的 codeigniter 文档也不是很精确(在一些小问题上,他们的代码示例在语法上并不是真正正确的,但总的来说它很好)。

我建议您首先将逻辑移动到将您的动态路由注册到它自己的函数中。这将使事情更加模块化,您可以更轻松地更改内容,并且不会用变量污染全局命名空间。

基于此,我对您的代码进行了一些重构。这并不意味着这有效(未经测试),但是当您阅读它时它可能会让事情变得更清楚:

function register_dynamic_routes($path, array &$route)
{
    $nodes = scandir($path);
    if (false === $nodes)
    {
        throw new InvalidArgumentException(sprintf('Path parameter invalid. scandir("$path") failed.', $path));
    }

    foreach ($nodes as $node)
    {
        if ($node === '.' or $node === '..')
            continue
            ;

        if (!is_dir("{$path}/{$node}")
            continue
            ;

        $routeDef = "{$folder}/(:any)";
        $routeResolve = "{$folder}/index/\$1";
        $route[$routeDef] = $routeResolve;

        # FIXME debug output
        echo "\$route['{$routeDef}'] = '{$routeResolve}';";
    }
}

$path = APPPATH.'controllers/';
register_dynamic_routes($path, $route);
$route['(:any)'] = 'main/index/$1';

在此旁边,您可能不想将所有内容都转移到 index 操作上,而是改为 dynamic 操作。此外,您可能希望拥有一个将所有内容委托给子控制器的基本控制器,而不是为每个控制器添加路由。但这取决于你。上面的示例基于您在问题中概述的目录方法。

编辑:更多信息可在Controllers section 旁边的URI Routing section 中获得

【讨论】:

  • 嗯,很好,但不工作,就像你说的。但是,你很好地解释了一切。谢谢。
【解决方案3】:

这一切似乎有点复杂。

另外,如果您在数据库中有数百(或数千或更多?)条可能的路由,您可能不希望每次在应用程序中加载任何页面时都将它们全部加载到“$routes”数组中。

相反,为什么不这样做呢?

routes.php的最后一行:

$route['404_override'] = 'vanity';

控制器文件:Vanity.php:

<?php
 defined('BASEPATH') OR exit('No direct script access allowed');

class Vanity extends MY_Controller {

/**
 * Vanity Page controller.
 *
 */

public function __construct() {
    parent::__construct();
}


public function index()
{
    $url = $_SERVER['PHP_SELF'];
    $url = str_replace("/index.php/", "", $url);

    // you could check here if $url is valid. If not, then load 404 via:
    //
    //  show_404();
    //
    // or, if it is valid then load the appropriate view, redirect, or
    // whatever else it is you needed to do!


    echo "Hello from page " . $url;
    exit;



}


}


?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多