Search code examples
phpcodeignitercodeigniter-4

Why autorouting (legacy) doesn't work in Codeigniter 4?


I have a project with a GET route included in the ‘Routes.php’ file and the rest of the routes generated by autorouting, that is, access to the methods of the controllers from the URL.

These controllers are included in a module. I created the following directory structure:

app 
├── Config       
│   └── Routes.php (refers to the routes created in each module folder /Config/Routes.php)
├── Modules      
│   └── Slink
|       ├──  Config
|           └──  Routes.php (Added a group with a single route)
│       ├──  Controllers
│           ├──  Home.php
|           └──  Shortener.php
│       ├──  Models
│           └──  Slink.php
│       └──  Views
│           ├──  not_found.php
|           └──  welcome_message.php
└── ...  

The code in app\Config\Routes.php is:

<?php

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */

 $modules_path = APPPATH . 'Modules/';
 $modules = scandir($modules_path);
 
 foreach ($modules as $module) {
     if ($module === '.' || $module === '..') {
         continue;
     }
 
     if (is_dir($modules_path) . '/' . $module) {
         $routes_path = $modules_path . $module . '/Config/Routes.php';
         if (file_exists($routes_path)) {
             require $routes_path;
         } else {
             continue;
         }
     }
 }

And the code in app\Modules\Slink\Config\Routes.php is the following:

<?php

namespace App\Modules\Slink\Config;

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */

 $routes->group(
    '', ['namespace' => 'App\Modules\Slink\Controllers'], function ($routes) {
        
        $routes->get('/', 'Home::welcome');
    }
);

When I try to access the GET route from the browser (http://localhost:8080/), it returns the expected result (content from the method welcome() in the Controller app\Modules\Slink\Controllers\Home.php) , but when I use the class/method route, it returns a 404 error (for example: http://localhost:8080/shortener/prueba). Do you know what could be happening?

The content of Controller app\Modules\Slink\Controllers\Shortener.php is:

<?php

namespace App\Modules\Slink\Controllers;

use App\Controllers\BaseController;

class Shortener extends BaseController
{
    public function prueba()
    {
        echo "HOLA MUNDO";
    }
}

And the content of Controller app\Modules\Slink\Controllers\Home.php is the following:

<?php

namespace App\Modules\Slink\Controllers;

use App\Controllers\BaseController;

class Home extends BaseController
{
    public function welcome(): string
    {
        return view('../Modules/Slink/Views/welcome_message');
    }
    
}

Result to try to access class/method route in the browser: 404 page

Attached is the result of the php spark routes command (where everything looks correct).

CodeIgniter v4.5.5 Command Line Tool - Server Time: 2025-01-27 13:33:43 UTC+00:00

+--------+-----------------------------+------+-------------------------------------------------------+----------------+---------------+
| Method | Route                       | Name | Handler                                               | Before Filters | After Filters |
+--------+-----------------------------+------+-------------------------------------------------------+----------------+---------------+
| GET    | /                           | »    | \App\Modules\Slink\Controllers\Home::welcome          |                |               |
| auto   | home/welcome[/...]          |      | \App\Modules\Slink\Controllers\Home::welcome          | <unknown>      | <unknown>     |
| auto   | shortener/prueba[/...]      |      | \App\Modules\Slink\Controllers\Shortener::prueba      | <unknown>      | <unknown>     |
+--------+-----------------------------+------+-------------------------------------------------------+----------------+---------------+

Required Before Filters: forcehttps, pagecache
 Required After Filters: pagecache, performance, toolbar

Solution

  • As the userguide suggests for Controllers (github.io) outside of the main app/Controllers directory, they cannot be automatically routed by URI detection.

    Given your routes registration:

    $routes->group(
        '', ['namespace' => 'App\Modules\Slink\Controllers'], function ($routes) {
            
            $routes->get('/', 'Home::welcome');
        }
    );
    

    You manage to set the default namespace to App\Modules\Slink\Controllers so that Home::welcome can be resolved to App\Modules\Slink\Controllers\Home::welcome which suffices to register the route for it, however you do not add the controller you're currently missing.

    What the spark routes function shows is that you successfully managed to register the default namespace for the controllers, which suffices for discovery of the routes, but the routing is only effective if the controller file is in the app/Controllers directory as unless the route can not be resolved (and henceforth you get a 404 File Not Found error).

    Just add the routes you'd actually like to configure:

    $routes->group(
        '', ['namespace' => 'App\Modules\Slink\Controllers'], function ($routes) {
            
            $routes->get('home/welcome', 'Home::welcome');
            $routes->get('shortener/prueba', 'Shortener::prueba');
        }
    );
    

    Or write your controllers as documented and in the places to work with autorouting (legacy).

    Additionally I'd recommend to also follow the suggestion about placing your module alongside the ./app directory, not inside:

    + raulizbu/slink/...
    + app/...
    

    See Code Modules (github.io), this should also help you not needing relying on self-written file discovery for your routes etc. as all you need to configure is the autoloading which also works per your projects composer.json instead of needing to hack the ./app/Config/Autoload.php file.