Welcome Guest, Not a member yet? Register   Sign In
Creating a database-driven dynamic route **SOLVED**
#1

[eluser]Dean Rantala[/eluser]
I am suprised I have not found more info on this subject, bet here we go.

Before anyone gets into Googleing: This is *not* pryoCMS and I would like this to function differently.

Now moving on...

At some point, Code Ignitor runs tests to determine what controller to use. What I would like to acomplish is:

1) Check the database for "/request/path" If a "page" exists in the database, re-map the controller to "application/controllers/cms.php.
2) If it does not exist in the database, continue as normal

Essentially - just as I have a rewrite rule that says "if it is not an existing file in the doc root, route the request to index.php", I would like to tell code igniter "if the request matches a database defined page, use the cms controller - otherwise, carry on as usual".

Note: for SEO reasons, I rather not have to create something like a pages.php controller and pass all CMS pages through /pages/page1, /pages/page2, etc..

- many thanks

P.S. Perhaps next CI version could include a "CMS hook" ? I would not mind tackling that myself it thats what it takes.
#2

[eluser]Dean Rantala[/eluser]
The more I look into this....

Perhaps I should:

Modify library/Router.php to include a check for $this->routes['cms_controller'] and if $this->uri->uri_string matches an entry for a vaild return from the defined cms_controller, have routing stop - otherwise, resume as normal.
#3

[eluser]Dean Rantala[/eluser]
**SOLVED**

This one needs to be a sticky.

Also suprised this is not a core feature.. but here we go:

1) Open system/libraries/Router.php
2) Around line 238 you will find "Can't find the requested controller"

This is our magic moment! Why.. oh why.. could the core devs not thing about letting you define a default "404 conntroller"?

3) Alter this:

// Can't find the requested controller...
show_404($segments[0]);

To look like this:

// Can't find the requested controller...
if( file_exists(APPPATH.'controllers/controllernotfound.php'))
{
$this->set_class('controllernotfound');
$this->set_method('index');
}
else
{
show_404($segments[0]);
}

Presto! Of coarse, you could get fancy and do a check to see if a default "404 controller" is defined in your config somewhere - but this gets the job done.

Now create a controllers/controllernotfound.php class and for the index method, do a "print 'it works'" or something to test.

You now have a central spot to test for a CMS page, perhaps run a Lucene search (for "page not found - but here are some similar search results"), or even just a really fancy 404 page.

Hope this helps

- Dean
#4

[eluser]eoinmcg[/eluser]
probably best to extend the router class in application/libraries/MY_Router.php rather than modifying the core.

also if you're going to produce your own 404 page don't forget to set the correct headers otherwise search engines will index it
#5

[eluser]n0xie[/eluser]
Our solution:

Code:
class MY_Router extends CI_Router {

    function MY_Router()
    {
        parent::CI_Router();
    }

    function _validate_request($segments)
    {
        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.$segments[0].EXT))
        {
            return $segments;
        }

        // Is the controller in a sub-folder?
        if (is_dir(APPPATH.'controllers/'.$segments[0]))
        {
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);

            if (count($segments) > 0)
            {
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
                {
                    show_404($this->fetch_directory().$segments[0]);
                }
            }
            else
            {
                $this->set_class($this->default_controller);
                $this->set_method('index');

                // Does the default controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
                {
                    $this->directory = '';
                    return array();
                }

            }


            return $segments;
        }

        // Let's check if there are database segments
        $segments = $this->dbrouting();

        // 404 hack
        if ($segments === FALSE)
        {
            //show_404($segments[0]) OR
            //redirect to controller 'page' invoking method 'page_not_found' for custom 404 handling
            $segments = array('page', 'page_not_found');
        }
        return $segments;
    }

    function dbrouting()
    {
        // do stuff here
    }
}
#6

[eluser]wiredesignz[/eluser]
Modular Extensions PHP5 and Modular Separation PHP5 version 1.9 using $route['404'].

application/libraries/My_Router.php
Code:
class MY_Router extends CI_Router
{
    private $module;
    
    public function fetch_module() {
        return $this->module;
    }
    
    public function _validate_request($segments) {        
        
        /* locate module controller */
        if ($located = $this->locate($segments)) return $located;
        
        /* application controller exists? */            
        if(is_file(APPPATH.'controllers/'.$segments[0].EXT)) {
            return $segments;
        }        
    
        list($directory, $controller) = array_pad($segments, 2, NULL);
        
        /* application sub-directory controller exists? */
        if(is_file(APPPATH.'controllers/'.$directory.'/'.$controller.EXT)) {
            $this->directory = array_shift($segments).'/';
            return $segments;
        }        
        
        /* use a default 404 controller */
        if (isset($this->routes['404']) AND $segments = explode('/', $this->routes['404'])) {
            
            /* locate 404 controller in a module? */
            if ($located = $this->locate($segments)) return $located;

            /* is 404 controller in application? */
            if (is_file(APPPATH.'controllers/'.$this->routes['404'].EXT)) {
                if (count($segments) > 1) $this->directory = array_shift($segments).'/';
                return $segments;
            }
        }
        
        /* no controller found */
        show_404();
    }

    public function locate($segments) { ... }
}
#7

[eluser]Phil Sturgeon[/eluser]
Sold, to the man in the hat!

This is a brilliant solution and one that came from me asking the same thing as the OP.

PyroCMS used to use a modified router, which would try looking for modules, sub-directories, controllers, and if if all that failed it would map it to the pages module. The pages module would do its checks for the db content and if that failed it fired show_404();

This is now pretty much the same flow, but it can be done without having to hack the Router (any more than the Modular Separation system already has).
#8

[eluser]n0xie[/eluser]
[quote author="wiredesignz" date="1258128690"]using $route['404'].[/quote]
Very nice. Never thought of doing it like that. Will implement it as well.
#9

[eluser]Dean Rantala[/eluser]
After looking into this some more, I considered this.

However, I think my first question [which was the purpose of the initial post] and the solution are kinda off-topic from each-other. But the even more interesting question/proposal is:

Why not be able to simply have a config directive in CI that tells is "If you cannot find a matching controller, use this DEFAULT controller/function instead - passing the full URI as an argument to the function". It seems to me this is core functionality that would save dozens of people from.. ehem.. duplicating code..

Example:

if( file_exists(APPPATH.'controllers/default_controller.php') && $this->config->item('global_default_controller') !=='' && <check for the existence of the controller..> ) {
<set everyhting to the default "fallback" controller>
} else {
.....
#10

[eluser]Phil Sturgeon[/eluser]
That is exactly what wiredesignz has implemented in his modular system. Whether you use it or not, we haven't gone off-topic in the slightest. Smile




Theme © iAndrew 2016 - Forum software by © MyBB