Page 1 of 1

MVC > Closest match action

Posted: Mon Feb 14, 2011 5:47 am
by MindOverBody
Last few days, i was designing my small MVC framework for my own educational purposes. Currently I am working on a Router class which is parsing URL address and provides array of Controller, Action and Parameters to the Dispatcher class which calls Controller, action and pass properties into action.

Ok, after this lightweight brief I am going to present you fat-ass Router method o'mine which main function is to make possible to load correct Action method although it is misspelled or shorten.

For example, this URL is requested:
http://www.mypage.com/Book/Shoooww/69/php-for-dummies
Router parses URL, and find that Book is controller, Shoooww should be action, 69 and php-for-dummies are parameters.
This questioned method makes checks for available actions and based on similarity picks one (Show). Code is well commented so I will explain no more :)

Here is the method code:

Code: Select all

          /**
           * This method searches over provided array of possible methods and based on
           * percent of similarity returns the closest match. If percent is lower than 30%
           * default method name is returned
           * @param string $action Provided action name via URL
           * @param array $methodArray Array of controller methods
           * @param string $defaultMethod Default method if match is not found
           * @access private
           */                                                                                       
          private function getClosestMatchMethod( $action, $methodArray, $defaultMethod ){
               // Check if provided parameters are valid
               if( is_string( $action ) && !empty( $action ) && is_array( $methodArray ) && is_string( $defaultMethod ) && !empty( $defaultMethod ) ){
                    // Initialize match array
                    $matchArray = array();
                    // Foreach of possible controller methods...
                    foreach( $methodArray as $method ){
                         // Check if method contains some 'magic' substrings
                         if( !strstr( $method, "__" ) || !strstr( $method, "_" ) ) {
                              // If method name is valid, calculate similarity between
                              // provided action candidate and possible controller methods
                              similar_text( $action, $method, $result );
                              // Store only matches that are over 30% similar
                              if( $result > 30 ) $matchArray[$method] = $result;
                         // Otherwise, continue
                         } else continue;
                    } 
                    // Check if any matches are founded
                    if ( !empty( $matchArray ) ){
                         // If founded, get maximum value in the string    
                         $maximum =& max( $matchArray );
                         // Return method name ( index key ) based on it's value
                         return array_search( $maximum, $matchArray, true );
                    // Otherwise return default method name
                    } else return $defaultMethod;
               // Otherwise, throw exception
               } else throw new Exception("Invalid parameter(s) in " . __METHOD__ );
          }
I am very interested in your opinion about this method. Is it good? Is it bad? Can I adjust something to gain speed? Ultimately, is it recommendable to use it? If you ask me, it is born for "hippie" links. :D

Re: MVC > Closest match action

Posted: Mon Feb 14, 2011 6:08 am
by Weirdan
This is wrong thing to do. Even if you guess user intention, you should validate it with the user. Moreover, you're violating HTTP protocol because accessing wrong url should produce 404.

On top of that your current scheme will get you penalized by search engines because you serve same content under more than one URL.

What you could do instead is present custom 404 page containing a list of links you guessed (and serve it with a proper 404 header of course).