Database driven routing in CodeIgniter 2.x

2020-02-26 02:36发布

问题:

I am creating a site that will have a lot of routes that will need to be added to the routes file (800+) - obviously I do not want to manually add these one by one into the routes config file.

Can anyone suggest the best practice to have my routes loaded automatically from the database. Is there a suitable library/helper that will perform this task that works with version 2.x

For instance..

$route['apple'] = 'brands/index';
$route['blackberry'] = 'brands/index';
$route['htc'] = 'brands/index';
$route['samsung'] = 'brands/index';

These are just a few of the brands i'd be adding to the routes - but there are hundreds of these so i'd want to have this loaded from a database rather than manually type these in. Also - would this method have any impact on site performance having them load from the database?

I am using Codeigniter v2.1.3

回答1:

If you were to constantly query the database (on each page load) via a DB call in the application/config/routes.php file then I imagine there would be a large impact on performance.

What I would suggest (and the way I have done this previously) is to include the following line at the bottom of your routes.php file and save all your routes to a routes.php file in the cache folder.

require_once APPPATH . 'cache/routes.php';

You can then write all your results to the cache file (using CI's file helper) with a function similar to the below:

public function save_routes() {
        $routes = $this->routes_model->get_all_routes();

        $data = array();

        if (!empty($routes )) {
            $data[] = '<?php if ( ! defined(\'BASEPATH\')) exit(\'No direct script access allowed\');';

            foreach ($routes as $route) {
                $data[] = '$route[\'' . $route['uri'] . '\'] = \'' . $route['controller'] . '/' . $route['action'] . '\';';
            }
            $output = implode("\n", $data);

            write_file(APPPATH . 'cache/routes.php', $output);
        }
    }

If you are adding new routes in an admin area, just run the above function each time you submit your new route and it will re-generate your routes cache file.

This method keeps your routes in application/config/routes.php intact, but allows you to write new routes to the cache file, without drastically affecting the performance of the site.

Hope that helps!!



回答2:

This is an old question but i was recently faced the same dilemma and found this answer useful.

http://osvaldas.info/smart-database-driven-routing-in-codeigniter

Create a table where you put all your routes

CREATE TABLE IF NOT EXISTS `app_routes` (
  `id` bigint(20) NOT NULL auto_increment,
  `slug` varchar(192) collate utf8_unicode_ci NOT NULL,
  `controller` varchar(64) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `slug` (`slug`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

Inside application/config/routes.php

//top two are the originals inside routes

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

//the new editions

require_once( BASEPATH .'database/DB'. EXT );
$db =& DB();
$query = $db->get( 'app_routes' );
$result = $query->result();
foreach( $result as $row )
{
$route[ $row->slug ]                 = $row->controller;
$route[ $row->slug.'/:any' ]         = $row->controller;
$route[ $row->controller ]           = 'error404';
$route[ $row->controller.'/:any' ]   = 'error404';
}

example i worked with INSERT INTO app_routes (slug, controller) VALUES ('about', 'pages/about');

or you can write a small cms to control your routes which is what i did as per the last bits on the website

id | slug  | controller  | actions
1  | about | pages/about | edit / delete


回答3:

I may have a solution to manage custom uri in a CI application.

Let say there is a table named "routes"

CREATE TABLE IF NOT EXISTS `routes` (
    `alias` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    `uri` VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    PRIMARY KEY (`alias`),
    UNIQUE(`alias`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

Then a custom "url helper" (application/helper/MY_url_helper.php)

// function that produces a safe uri
if( ! function_exists('safe_uri'))
{
    function safe_uri($str, $replace=array(), $delimiter='-') {
        if( !empty($replace) ) {
            $str = str_replace((array)$replace, ' ', $str);
        }

        $clean = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
        $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
        $clean = strtolower(trim($clean, '-'));
        $clean = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

        return $clean;
    }
}
// overriden function that checks if the uri exists in the routing table. If so, use this uri instead
if ( ! function_exists('site_url'))
{
    function site_url($uri = '')
    {
        $CI =& get_instance();
        if(in_array($uri, $CI->router->routes)){
            $key = array_search($uri, $CI->router->routes);
            if($key)$uri=$key;
        }
        return $CI->config->site_url($uri);
    }
}

Then a library I called 'route_manager' that creates / modifies a route and generate the custom route.php file (application/libraries/route_manager.php, creates application/cache/routes.php)

Note : Your app must be able to write files in 'application/cache'

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

class route_manager{

    public function set_alias($full_text, $uri){
        $this->load->helper('url');
        $sql = 'INSERT INTO `routes` (`alias`, `uri`) VALUES(?,?)
                ON DUPLICATE KEY UPDATE
                uri=VALUES(uri)';
        $this->db->query($sql, array(safe_uri($full_text), $uri));
    }

    public function create_routes_file(){
        $res = $this->db->get('routes');
        $output = '<' . '?' . 'php ' . 'if ( ! defined(\'BASEPATH\')) exit(\'No direct script access allowed\');' . CRLF . CRLF;
        foreach($res->result_array() as $rs){
            $output .= '$' . 'route[\'' . $rs['alias'] . '\'] = "' . $rs['uri'] . '";'. CRLF;
        }
        // unsure the file won't generate errors
        $route = array();
        eval('?> '.$output);
        // if error detected, the script will stop here (and won't bug the entire CI app). Otherwize it will generate the cache/route.php file
        $this->load->helper('file');
        write_file(APPPATH . 'cache/routes.php', $output);
    }

}

Then add a require_once (the 4th line in the example below) in your application/config/ routes.php file

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

// require custom routes (if the file exists)
if(file_exists(APPPATH . 'cache/routes.php'))require_once(APPPATH . 'cache/routes.php');

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

All will work using nice uri!

Exemple to create a custom fiendly uri, let's say 'super page that ROCKS! (really)' must be routed to "page" controller, "index" function with '23' as a parameter :

$this->load->library('route_manager');
$this->route_manager->set_alias('super page that ROCKS! (really)', 'page/index/23');
$this->route_manager->create_route_file();

Example to use that custom uri

echo site_url('page/index/23');

This example will generate a friendly and working url like this:

http://www.yourwebsite.com/index.php/super-page-that-rocks-really