CodeIgniter Forums
Routing dynamic controller with placeholder - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: CodeIgniter 4 (https://forum.codeigniter.com/forum-28.html)
+--- Forum: CodeIgniter 4 Feature Requests (https://forum.codeigniter.com/forum-29.html)
+--- Thread: Routing dynamic controller with placeholder (/thread-76429.html)



Routing dynamic controller with placeholder - timanon - 05-12-2020

I was struggling with a Placeholder for the Controller, what I wanted to achieve is to define the controller in the URL like this:
PHP Code:
$routes->get('{locale}/(:segment)''$1::index'); 


This doesn't work because of the Router, which replaces the Placeholder with preg_replace and the backslash of the generated Namespace tells it, to ignore the next special character:
input:
\App\Controllers\$1::index
output:
\App\Controllers$1::index

To solve the problem, i did rewrite a small piece of code in the Router.php, line 467:
Old code:
PHP Code:
if (strpos($val'$') !== false && strpos($key'(') !== false && strpos($key'/') !== false) {
    $replacekey str_replace('/(.*)'''$key);
    $val preg_replace('#^' $key '$#'$val$uri);
    $val str_replace($replacekeystr_replace('/''\\'$replacekey), $val);
} elseif (
strpos($val'$') !== false && strpos($key'(') !== false) {
    $val preg_replace('#^' $key '$#'$val$uri);
} elseif (
strpos($val'/') !== false) {
    [
            $controller,
            $method,
            ] = explode('::'$val);

    // Only replace slashes in the controller, not in the method.
    $controller str_replace('/''\\'$controller);

    $val $controller '::' $method;


New code:
PHP Code:
if (strpos($val'$') !== false && strpos($key'(') !== false) {
    // Tell preg_replace to consider the backslash as a literal character.
    $val str_replace('\\''\\\\'$val);
    $val preg_replace('#^' $key '$#'$val$uri);
    if (strpos($key'/') !== false) {
        $replacekey str_replace('/(.*)'''$key);
        $val str_replace($replacekeystr_replace('/''\\'$replacekey), $val);
    }
}

// Replace slashes in the controller with backslashes and capitalize the first letter.
[$controller$method,] = explode('::'$val);
$controller str_replace('/''\\'$controller);
$controller ucwords($controller'\\');
$val $controller '::' $method

In addition to dynamic controllers it's also possible to nest the controllers inside the Namespace.
Following routes are working:

PHP Code:
$routes->get('{locale}/(:segment)''$1::index');

$routes->get('{locale}/(:segment)''Home/$1::index'); 



It would be nice to add this or something similar to the official version.


RE: Routing dynamic controller with placeholder - kilishan - 05-12-2020

That's not a feature that we're interested in adding to the Routing system due to security concerns. If you need that type of matching you can do that with the auto-matching like all previous versions of CodeIgniter have had.


RE: Routing dynamic controller with placeholder - timanon - 05-12-2020

I came to this issue because of the language segment, according to Google SEO it's recommended to have this in the URL. I try to negotiate the language if none is defined and reload the page with the evaluated one. So the first segment is always the {local} segment.
Another solution would be to offset the auto-routing like this:

$routes->setAutoRoute(true, 1); \\ second parameter as the offset, first segment is ignored.

Would that be a better solution? Or is there another/better way without defining all routes?