Welcome Guest, Not a member yet? Register   Sign In
Another Route Regex
#1

[eluser]Torus[/eluser]
I am trying to create search engine friendly URLs for my CI app.

I would prefer to write URLs with hyphens, controller-name/function-name/other-stuff/n-levels-deep

Obviously I can't have controllers or functions with hyphens in their names... The solution I've seen is to use a route to send these requests to the right place:
$route['controller-name/function-name/(.*)'] = 'controller_name/function_name/$1';

Here's the tricky part: I don't want to write a new route for every single controller in my app. Is there a way to write a route that would replace the hyphens with underscores for the first two segments?

controller-name/function-name/other-stuff/and-more --> controller_name/function_name/other-stuff/and-more

Something that would basically act like this (but actually work, this doesn't quite):

$route['(.*)/(.*)/(.*)'] = str_replace('-', '_', "$1") . "/" . str_replace('-', '_', "$2") . "/$3";
#2

[eluser]xwero[/eluser]
You almost had the solution
Code:
$route['([a-zA-Z]+)-([a-zA-Z]+)/([a-zA-Z]+)-([a-zA-Z]+)(.*)'] = '$1_$2/$3_$4$5'; // $5 is 'optional'
This is only in case the controller and the method both have one hyphen. You are going to need variations on the route to get other hyphened controllers and methods.
#3

[eluser]TheFuzzy0ne[/eluser]
I'd suggest that you extend the Router class. Smile
#4

[eluser]xwero[/eluser]
Why? i guess there won't be too many of those hyphened controllers because a part is already split by the method names, for example blog/add - blog/edit - blog/archive - and so on.
And methods should be as short as possible, you're going to use something like blog/blog-add.

I think it's best to create specific routes instead of cache-all routes because if you give controllers and methods short but descriptive the need for routes like this will be minimal.
#5

[eluser]Torus[/eluser]
@xwero - there we go. That should do the trick, certainly while I am try to get things working. Like you said, I'll need other routes if I want more hyphens, but it would only be one extra route per extra hyphen. That should be pretty manageable. Short, descriptive names are awesome for controllers and methods, but there are a few cases where I will need a longer, SEO based name. There would only ever need to be a few controllers and a few functions per project with this case, but if you had say 6 controllers and 3 or 4 functions a piece that needed hyphens, you'd end up with 24 individual routes instead of 1-6 routes with regular expressions to do it automatically.

@TheFuzzyOne - I will look into using the router class for this - I've done a little work with it already, so we'll see if I can tweak it to do N hyphens and skip the need for special routes altogether.

Thanks guys. I'll post what I come up with.
#6

[eluser]Torus[/eluser]
I think I've come up with a solution that meets my requirements for SEO-friendly URLs.

The URL MUST be written in the following form:
http://www.website.com/folders-that/are-...page-name/

Further, I have two goals for my sites that use Code Igniter - I want to be able to create controllers and functions for applications (like Code Igniter was meant to), and I want to create lots of content pages that are served by Code Igniter from a database without having to create separate controllers for each part of the site that is a content section (support, about us, etc.).

I didn't want the URLs for content pages to be limited by the default folder, controller, function, or segment conventions that exist in Code Igniter, but I also didn't want to break Code Igniter's default functionality for application-centric stuff. This necessitated three changes to how Code Igniter handles routing. All of them were achieved by extending the Router class.

1. Controllers in folders nested n-deep - solved using the controller nesting code from Peter Goodman.

2. A default controller that would catch any request that didn't resolve as another controller and check to see if it was a content page request - solved using Adam Jackett's (darkhouse) modification of Peter's code.

3. Controllers and functions that had hyphens in the url that requested them. I modified Peter and Adam's code to test each segment that was possibly a controller or function. It works by creating a temporary copy of the segment with all of the hyphens changed to underscores. If the segment resolves to a controller, then the change to the segment is made permanent - otherwise, it is discarded and the path is parsed further.

I'll include the code in my next post.
#7

[eluser]Torus[/eluser]
Code:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
* Router Extension for SEO-friendly URLS
* Discussion threat at:http://ellislab.com/forums/viewthread/113899/
* @author Michael Ebert
* @copyright Copyright 2009 Michael Ebert, all rights reserved.
*
* Controllers in unlimited nesting of folders by Peter Goodman, 2007
* Discussion thread at: http://ellislab.com/forums/viewthread/56100/
*
* Catch-all controller capability by Adam Jackett, 2009
* Discussion thread at: http://ellislab.com/forums/viewthread/107451/
*
* SEO-friendly controller and function names (for using hyphens in URLs)  by Michael Ebert, 2009
* Discussion threat at:http://ellislab.com/forums/viewthread/113899/
*/

class MY_Router extends CI_Router
{
    function _pluck_directory($segments)
    {
        $this->directory = '';
        
        foreach($segments as $segment)
        {
            $segment = trim($segment);
            if($segment != '')
            {
                if(is_dir(APPPATH .'controllers/'. $this->directory . $segment))
                {
                    $this->directory .= array_shift($segments) .'/';
                }
                else
                {
                    break;
                }
            }
            else
            {
                array_shift($segments);
            }
        }
        
        // quick and easy forced reindexing
        $segments = array_values($segments);
        
        // put the entire directory path back into the segments as the first item
        $dir = trim($this->directory, '/');
        if(!empty($dir))
        {
            array_unshift($segments, $dir);
        }
        
        $this->segments = $segments;
        
        return $segments;
    }

    function _validate_request($segments)
    {
        $segments = $this->_pluck_directory($segments);
        $found = TRUE;
        
        // Use to test if the controller exists with hyphens switched to underscores
        $test_segment = str_replace('-', '_', $segments[0]);
        
        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.$test_segment.EXT))
        {    
            // Make the change to the controller name permanent
            $segments[0] = str_replace('-', '_', $segments[0]);
            
            // Since we've found the controller, we need to make sure its function call also has hyphens switched to underscores
            if (isset($segments[1]))
            {
                $segments[1] = str_replace('-', '_', $segments[1]);
            }
            
            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)
            {
                // Use to test if the controller exists with hyphens switched to underscores
                $test_segment = str_replace('-', '_', $segments[0]);
                
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$test_segment.EXT))
                {
                    $found = FALSE;
                }
                else
                {
                    // Make the change to the controller name permanent
                    $segments[0] = str_replace('-', '_', $segments[0]);    
                    
                    // Since we've found the controller, we need to make sure its function call also has hyphens switched to underscores
                    if (isset($segments[1]))
                    {
                        $segments[1] = str_replace('-', '_', $segments[1]);
                    }
                }
            }
            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();
                }
            }
            
            if($found) return $segments;
        }
        
        // Can't find the requested controller, so fall back to the default
        // The default controller would be responsible for either serving a content page or the 404 page.
        $this->set_directory('');
        $this->set_class('pages');
        $this->set_method('index');
        return array();
    }
}

?>
#8

[eluser]darkhouse[/eluser]
It's interesting to me to see the different uses my little mod comes in handy for. I originally made it obviously for a CMS system, however before I had the CMS part of my project done, we had already used it to solve another problem which was converting a medium sized site to code igniter. We converted everything that was absolutely crucial like the user system and a bunch of other things, but then had a good number of content pages that were still using the old database, etc. We used this mod to take the request like site.com/somepage.php, parse the resulting html, strip out the content, and display it in a custom view. We also got it to use old css and javascript files as well as reading GET and POST requests.

Anyways, I'm glad it has served yet another purpose.
#9

[eluser]markwyner[/eluser]
Hello,

Torus' router extension works like absolute magic but only on some servers. I didn't assume this would have any server dependencies, but it only works on one of two servers where I test it.

It breaks down only with the class segment, yet all others work fine. So:

/class-name/

Does not work (throws a 404). Yet:

/class-name/whatever-function/

Works fine. And, again, this works flawlessly on my local server in its entirety (including the class segment). But when I push it to a remote server it breaks as I've mentioned.

Any ideas why this might be the case? I can post a phpinfo file if there is indeed a dependency.

Thanks in advance for any help.
#10

[eluser]darkhouse[/eluser]
Possibly the trailing slash?




Theme © iAndrew 2016 - Forum software by © MyBB