Asked  2 Years ago    Answers:  5   Viewed   145 times

I'm looking for a one line route to route dashed controller and method names to the actual underscored controller and method names.

For example the URL

/controller-name/method-name-which-is-long/

would route to

/controller_name/method_name_which_is_long/

see: http://codeigniter.com/forums/viewreply/696690/ which gave me the idea to ask :)

 Answers

2

That is exactly my requirement too and I was using routes like

$route['logued/presse-access'] = "logued/presse_access";

In my previous project I needed to create 300-400 routing rules, most of them are due to dash to underscore conversion.

For my next project I eagerly want to avoid it. I have done some quick hack and tested it, though have not used in any live server, its working for me. Do the following..

Make sure the subclass_prefix is as follows in your system/application/config/config.php

$config['subclass_prefix'] = 'MY_';

Then upload a file named MY_Router.php in system/application/libraries directory.

<?php

class MY_Router extends CI_Router { 
    function set_class($class) 
    {
        //$this->class = $class;
        $this->class = str_replace('-', '_', $class);
        //echo 'class:'.$this->class;
    }

    function set_method($method) 
    {
//      $this->method = $method;
        $this->method = str_replace('-', '_', $method);
    }

    function _validate_request($segments)
    {
        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $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().str_replace('-', '_', $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;
        }

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

Now you can freely use url like http://example.com/logued/presse-access and it will call the proper controller and function by automatically converting dash to underscore.

Edit: Here is our Codeigniter 2 solution which overrides the new CI_Router functions:

<?php

class MY_Router extends CI_Router { 
    function set_class($class) 
    {
        $this->class = str_replace('-', '_', $class);
    }

    function set_method($method) 
    {
        $this->method = str_replace('-', '_', $method);
    }

    function set_directory($dir) {
        $this->directory = $dir.'/';
    }

    function _validate_request($segments)
    {
        if (count($segments) == 0)
        {
            return $segments;
        }

        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).'.php'))
        {
            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);


            while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
            {
                // Set the directory and remove it from the segment array
                $this->set_directory($this->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().str_replace('-', '_', $segments[0]).'.php'))
                {
                    if ( ! empty($this->routes['404_override']))
                    {
                        $x = explode('/', $this->routes['404_override']);

                        $this->set_directory('');
                        $this->set_class($x[0]);
                        $this->set_method(isset($x[1]) ? $x[1] : 'index');

                        return $x;
                    }
                    else
                    {
                        show_404($this->fetch_directory().$segments[0]);
                    }
                }
            }
            else
            {
                // Is the method being specified in the route?
                if (strpos($this->default_controller, '/') !== FALSE)
                {
                    $x = explode('/', $this->default_controller);

                    $this->set_class($x[0]);
                    $this->set_method($x[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.'.php'))
                {
                    $this->directory = '';
                    return array();
                }

            }

            return $segments;
        }


        // If we've gotten this far it means that the URI does not correlate to a valid
        // controller class.  We will now see if there is an override
        if ( ! empty($this->routes['404_override']))
        {
            $x = explode('/', $this->routes['404_override']);

            $this->set_class($x[0]);
            $this->set_method(isset($x[1]) ? $x[1] : 'index');

            return $x;
        }


        // Nothing else to do at this point but show a 404
        show_404($segments[0]);
    }
}

Now one has to place this file like application/core/MY_Router.php and make sure he has subclass_prefix is defined as $config['subclass_prefix'] = 'MY_'; in application/config/config.php

Few extra lines of code has been added in method _validate_request():

while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
    // Set the directory and remove it from the segment array
    $this->set_directory($this->directory . $segments[0]);
    $segments = array_slice($segments, 1);
}

It is used so that one can make use of multi-level subdirectory inside controllers directory, whereas normally we can use single level subdirectory inside controllers folder and can call it in url. One can remove this code if it not necessary but it has no harm on the normal flow.

Saturday, October 22, 2022
4

When you set the validation rules you separate them with a | so the |'s in your regex is causing the validation rule to split at those and that is causing the error. Discussion here on the issue. It seems it's a limitation or bug in codeigniter. You can test it out by running a regex with and without |'s and see if the usage of pipes will cause an error. If that is the case then you may have to validate by regex by other means, maybe use a callback function as detailed on this page where your function will do a preg_match using the regex which needs to be inside the function of course and then return true/false.

Saturday, December 3, 2022
 
2

Generally in Objective-C you create a designated initializer for each class and then subclasses use the same initializer. So instead of using initAnimal and initDog, you just use init. The dog subclass would then define its own init method and call the designated initializer in its parent class:

@implementation Dog
-(id)init
{
    if( (self = [super init]) ) {  // call init in Animal and assign to self
        // do something specific to a dog
    }
    return self;
}
@end

You don't really have to specify initDog and initAnimal because the class is declared on the right hand side of the assignment...

Update: I'm adding the following to the answer to reflect the additional information in the question

There are a number of ways to ensure that subclasses don't call initializers other than their designated initializer and the way you ultimately choose will be largely based on your whole design. One of the nice things about Objective-C is that it's so flexible. I will give you two examples here to get you started.

First, if you create a subclass that has a different designated initializer than its parent class, you can overload the parent's initializer and throw an exception. This will let programmers know immediately that they've violated the protocol for your class... however, it should be stated that you should have a very good reason for doing this and that it should be very well documented that the subclass may not use the same initializer as the superclass.

@implementation Dog
-(id)init
{
    // Dog does not respond to this initializer
    NSAssert( false, @"Dog classes must use one of the designated initializers; see the documentation for more information." );

    [self autorelease];
    return nil;
}

-(id)initWithFur:(FurOptionsType)furOptions
{
    if( (self = [super init]) ) {
        // do stuff and set up the fur based on the options
    }
    return self;
}
@end

Another way to do it is to have initializer more like your original example. In that case, you could change the default init on the parent class to always fail. You could then create a private initializer for your parent class and then make sure everyone calls the appropriate initializer in subclasses. This case is obviously more complicated:

@interface Animal : NSObject
-(id)initAnimal;
@end

@interface Animal ()
-(id)_prvInitAnimal;
@end

@interface Dog : Animal
-(id)initDog;
@end

@implementation Animal
-(id)init
{
    NSAssert( false, @"Objects must call designated initializers; see documentation for details." );

    [self autorelease];
    return nil;
}

-(id)initAnimal
{
    NSAssert( [self isMemberOfClass:[Animal class]], @"Only Animal may call initAnimal" );

    // core animal initialization done in private initializer
    return [self _prvInitAnimal];
}

-(id)_prvInitAnimal
{
    if( (self = [super init]) ) {
        // do standard animal initialization
    }
    return self;
}
@end

@implementation Dog
-(id)initDog
{
    if( (self = [super _prvInitAnimal]) ) {
        // do some dog related stuff
    }
    return self;
}
@end

Here you see the interface and implementation of the Animal and Dog class. The Animal is the designated top-level object and therefore overrides NSObject's implementation of init. Anyone who calls init on an Animal or any of Animal's subclasses will get an assertion error referring them to the documentation. Animal also defines a private initializer on a private category. The private category would stay with your code and subclasses of Animal would call this private initializer when they call up to super. It's purpose is to call init on Animal's superclass (NSObject in this case) and to do any generic initialization that might be necessary.

Finally, the first line in Animal's initAnimal method is an assertion that the receiver is actually an Animal and not some subclass. If the receiver is not an Animal the program will fail with an assertion error and the programmer will be referred to the documentation.

These are just two example of how you might design something with your specific requirements. However, I would strongly suggest you consider your design constraints and see if you really require this type of design as it's non-standard in Cocoa and in most OO design frameworks. For instance, you may consider making various animals root-level objects and just have an Animal protocol instead, requiring that all of the various "animals" respond to certain animal-generic messages. That way each animal (and true subclasses of Animal) can handle their designated initializers themselves and won't have to rely on superclasses behaving in such a specific, non-standard manner.

Thursday, October 6, 2022
4

I think you've written your htaccess regexp rule wrong. You don't need to write it as a PHP regexp rule, try to rewrite it without the slash in your htaccess:

RewriteRule ^([a-z]{2})/page$ /index.php/locale/somepage

This will send any http://mypage.com/en/page to index.php/locale/somepage.

With that rule, CI will receive the url index.php/locale/somepage. At that point, CI will go to routes.php and will check if there are any rule to call a specific controller. If not, it'll try to go to a controller called locale, to load a method called somepage.

So, you don't need to use routes.php to modify again the apache url that you're receving to call another controller.

Wednesday, August 24, 2022
 
bulat
 
4

The problem is that you need to use the this keyword in your js. Otherwise you will just be getting the element with the first occurence of that class. Also considering all of your input fields have the 'btn' class why don't you change your js to

$(".btn").click(function(){
   //Use 'this' to get the value of the element you clicked on
   alert($(this).val());
});

Note You are looping through your rows in your PHP code but each time giving the elements the same id (id="enable" and id="disabled"). This will cause multiple elements to have the same id, which will invalidate your HTML and could cause you problems later on.

Sunday, October 30, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 

Browse Other Code Languages