-
W140 Newbie

-
Posts: 4
Threads: 1
Joined: Sep 2015
Reputation:
0
Hello there,
I'm trying to archieve to create custom url for specific content.
For example, i have blog and page tables in my database.
URL structure for the blog posts is "example.com/blog/view/post-slug-here" and it's working as intended.
Exclusively for page content, i want to create a URL structure like "example.com/page-slug-here".
Since this route taking priority over all rules:
PHP Code: $route['(:any)'] = 'page/view/$1';
I couldn't managed to archieve it so far.
In fact, i can archieve this this 404_override. But i have doubt that i'll have trouble when things getting complex.
For example, when i need to create sub site as follows:
Code: "example.com/sub-site"
"example.com/sub-site/blog/view/post-slug-here"
"example.com/sub-site/controller/method"
Probably i need to route sub-site's "example.com/sub-site/ page-slug-here" to a controller other than 404_override.
What is the best way to archieve this?
-
mwhitney Posting Freak
    
-
Posts: 1,101
Threads: 4
Joined: Nov 2014
Reputation:
95
09-25-2015, 10:41 AM
(This post was last modified: 09-25-2015, 10:42 AM by mwhitney.)
I'm not sure I completely understand your issue, but any route which is specifically defined in the routes config will be matched before any RegEx rules are evaluated (':any' or ':num' is converted to a RegEx). So, if you have:
Code: $route['sub-site'] = 'sub_site';
Then example.com/sub-site will work. Of course, that still creates an issue for the routes beneath it (example.com/sub-site/blog, etc.). For that, you would need to define another RegEx route for your sub-site, which means the router will loop through the list of RegEx routes until it finds a match.
This means that you need to define your RegEx routes in order from the most specific to the least specific in order to correctly match a route. So, your sub-site RegEx must be defined before your '(:any)' route. Once you do this, the only issue you should run into is that you won't be able to use 'sub-site' as a slug unless you use the URL example.com/page/view/sub-site.
-
Muzikant Member
  
-
Posts: 173
Threads: 21
Joined: Feb 2015
Reputation:
2
09-25-2015, 10:47 AM
(This post was last modified: 09-25-2015, 10:53 AM by Muzikant.)
Try something like this:
PHP Code: $route['controller-1/method-1/(:any)'] = 'controller-1/method-1/$1'; $route['controller-2/(:any)'] = 'controller-2/method-2/$1'; $route['(:any)'] = 'controller-3/method-3/$1';
You can also use:
PHP Code: $route['something-1/controller-1/method-1/(:any)'] = 'controller-1/method-1/$1'; $route['something-2/controller-2/(:any)'] = 'controller-2/method-2/$1'; $route['something-3/(:any)'] = 'controller-3/method-3/$1';
If you did not, read the URI Routing in the documentation, where you can find more tips.
-
W140 Newbie

-
Posts: 4
Threads: 1
Joined: Sep 2015
Reputation:
0
Thank you for your interest @ mwhitney.
Let me be more specific on the issue.
Let's say,
i'm showing list of blog posts on example.com/blog which points to controller/Blog.php->index()
and, i'm showing single blog post on example.com/blog/view/post-slug-here which points to controller/Blog.php->view($slug)
and maybe my contact page on example.com/contact which points to controller/Contact.php->index()
these are expected behaviour of CI and should work perfecty.
in addition to this scenario, (blog and contact page) there is another content (eg: page table on database) which i want to serve from url pattern like this: "example.com/page-title"
there maybe tens of dynamic content. so i cannot create controller for each of these content.
Exaple Page Table
Code: ID TITLE CONTENT
1 brown-fox The quick brown fox jumps over the lazy dog
2 fox-origin The quick brown fox jumps over the lazy dog
..
99 where-is-lazy The quick brown fox jumps over the lazy dog
To archieve this behaviour i tried following route:
PHP Code: $route['(:any)'] = 'page/view/$1';
Since this approach archieves my needs, it's also breaking other blogs/pages etc.
Because any string just after example.com/anystring routing to [b]controller/Page.php->view($title)[/b]
So, is there a way to tell to CI that,
1) If requested controller/method exists, execute it. ( eg: example.com/blog => controller/Blog.php->index() )
2) And in case if it's not exists , execute a specified controller/method.
-
W140 Newbie

-
Posts: 4
Threads: 1
Joined: Sep 2015
Reputation:
0
(09-25-2015, 11:21 AM)Martin7483 Wrote: I think you are looking for a catch all controller. When a /db-page-slug does not match any “physical” controller the system falls back on this catch all controller. With this controller you can then perfrom a DB search for the given slug. If still nothing is found you can revert to your 404 controller
Yes, this is one of the things that i want to archieve.
Could you please help me on "catch all controller" because i couldn't find any info about it.
-
W140 Newbie

-
Posts: 4
Threads: 1
Joined: Sep 2015
Reputation:
0
Hello again;
Thanks for everyone who tried to help me in this thread.  I appreciate your interest.
I've solved my issue with following approach. (I know it's a little bit dirty but i couldn't find an elegant solution to this.)
PHP Code: $route['(:any)'] = function($slug) { // find out which class(controller)/method to execute. $validated = $this->_validate_request( array_values($this->uri->segments) ); // cleanup. (which set by _validate_request()) $directory = $this->directory; $this->directory = NULL;
// extract class(controller) & method name. if(array_key_exists(0,$validated)) { // class(controller) name found. $class_name = ucfirst($validated[0]); } else { // class(controller) name not found. route to desired controller. return 'page/view/'.$slug; } $method_name = array_key_exists(1,$validated) ? $validated[1] : 'index'; // class(controller) file to load. $class_path = APPPATH.'controllers/'. $directory . $class_name . '.php'; // cleanup. (which set by _validate_request()) $this->directory = NULL; // class(controller) exists? if(file_exists($class_path)) { // load CI_Controller core class and our class(controller). include_once(FCPATH.'system/core/Controller.php'); include_once($class_path); // does method exists? if(method_exists($class_name,$method_name)) { // if class(controller) and method exists, we should execute it. return implode('/',$this->uri->segments); } else { // well, if not, it's time to route to desired controller. return 'page/view/'.$slug; } } else { // if class(controller) doesnt exists, route to desired controller. return 'page/view/'.$slug; } };
This code works as follows:
Scenario: Physically Exists
example.com/controller/method => controllers/Controller.php->method();
example.com/controller => controllers/Controller.php->index();
Scenario: Not Exists
example.com/non-controller => controllers/page.php->view($slug);
Sub-Site Example
PHP Code: $route['subsite/(:any)'] = /* same code as above */
Scenario: Physically Exists
example.com/subsite/controller/method => controllers/subsite/Controller.php->method();
example.com/subsite/controller => controllers/subsite/Controller.php->index();
Scenario: Not Exists
example.com/subsite/non-controller => controllers/page.php->view($slug);
-
Martin7483 Crossfire CMS
   
-
Posts: 373
Threads: 14
Joined: Sep 2015
Reputation:
20
Hi,
I see you have found a solution. Should you still be interested in using a catch all controller I have been able to extend the core Router class to make use of this option.
Add the following line to your routes.php config file in ./application/config
PHP Code: $route['catchall_controller'] = 'your_catch_all';
Copy MY_Router.php and add it to your ./application/core directory
PHP Code: <?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/** * My Router * * This class extends the Crossfire core Router. It adds a catch all * controller for routing DB pages * * @author Martin Langenberg */
class MY_Router extends CI_Router { /** * Catchall controller * * @var string */ public $catchall_controller; public function __construct() { log_message('debug', "Class ".get_class($this)." Initialized."); parent::__construct(); } /** * Set route mapping * * Determines what should be served based on the URI request, * as well as any "routes" that have been set in the routing config file. * * @return void */ protected function _set_routing() { // Are query strings enabled in the config file? Normally CI doesn't utilize query strings // since URI segments are more search-engine friendly, but they can optionally be used. // If this feature is enabled, we will gather the directory/class/method a little differently if ($this->enable_query_strings) { // If the directory is set at this time, it means an override exists, so skip the checks if ( ! isset($this->directory)) { $_d = $this->config->item('directory_trigger'); $_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : ''; if ($_d !== '') { $this->uri->filter_uri($_d); $this->set_directory($_d); } } $_c = trim($this->config->item('controller_trigger')); if ( ! empty($_GET[$_c])) { $this->uri->filter_uri($_GET[$_c]); $this->set_class($_GET[$_c]); $_f = trim($this->config->item('function_trigger')); if ( ! empty($_GET[$_f])) { $this->uri->filter_uri($_GET[$_f]); $this->set_method($_GET[$_f]); } $this->uri->rsegments = array( 1 => $this->class, 2 => $this->method ); } else { $this->_set_default_controller(); } // Routing rules don't apply to query strings and we don't need to detect // directories, so we're done here return; } // Load the routes.php file. if (file_exists(APPPATH.'config/routes.php')) { include(APPPATH.'config/routes.php'); } if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/routes.php')) { include(APPPATH.'config/'.ENVIRONMENT.'/routes.php'); } // Validate & get reserved routes if (isset($route) && is_array($route)) { isset($route['default_controller']) && $this->default_controller = $route['default_controller']; // Set the catch all controller isset($route['catchall_controller']) && $this->catchall_controller = $route['catchall_controller']; isset($route['translate_uri_dashes']) && $this->translate_uri_dashes = $route['translate_uri_dashes']; unset($route['default_controller'], $route['translate_uri_dashes'], $route['catchall_controller']); $this->routes = $route; } // Is there anything to parse? if ($this->uri->uri_string !== '') { $this->_parse_routes(); } else { $this->_set_default_controller(); } } /** * Set request route * * Takes an array of URI segments as input and sets the class/method * to be called. * * @used-by CI_Router::_parse_routes() * @param array $segments URI segments * @return void */ protected function _set_request($segments = array()) { $segments = $this->_validate_request($segments); // If we don't have any segments left - try the default controller; // WARNING: Directories get shifted out of the segments array! if (empty($segments)) { $this->_set_default_controller(); return; }
if ($this->translate_uri_dashes === TRUE) { $segments[0] = str_replace('-', '_', $segments[0]); if (isset($segments[1])) { $segments[1] = str_replace('-', '_', $segments[1]); } }
$this->set_class($segments[0]); if (isset($segments[1])) { $this->set_method($segments[1]); } else { $segments[1] = 'index'; } // Check if a valid controller is set, else call the catchall if( ! $this->_is_controller($segments[0]) ) { $this->_set_catchall_controller(); return; }
array_unshift($segments, NULL); unset($segments[0]); $this->uri->rsegments = $segments; } /** * Set default controller * * @return void */ protected function _set_catchall_controller() { // Catch all controller empty? Set the default controller if (empty($this->catchall_controller)) { $this->_set_default_controller(); } // Is the method being specified? if (sscanf($this->catchall_controller, '%[^/]/%s', $class, $method) !== 2) { $method = 'index'; } if ( ! file_exists(APPPATH.'controllers/'.$this->directory.ucfirst($class).'.php')) { // No file found for the catch all controller $this->_set_default_controller(); } $this->set_class($class); $this->set_method($method); // Assign routed segments, index starting from 1 $this->uri->rsegments = array( 1 => $class, 2 => $method, 3 => implode('/', $this->uri->segments) ); log_message('debug', "No matching controller. Catch all controller {$this->catchall_controller} set."); } protected function _is_controller($controller) { $dir = realpath(APPPATH.'controllers/'.$this->directory); if( ! file_exists(realpath($dir.'/'.$controller.'.php')) ) { // Clear, or set the directory for the use of the catchall controller $this->set_directory(NULL); return FALSE; } return TRUE; } }
|