Search code examples
phpcodeignitercodeigniter-4

CodeIgniter4 namespace repeating itself: Controller or its method is not found: \\App\\Controllers\\App\\Controllers\\TypeBloodController::index


I am unable to create a Restful API using the CodeIgniter 4 framework.
I am using $routes->resource() to define the methods. However, I am unable to get http://localhost:8080/type-blood and other addresses to return what I want.

I correctly configured the database in the project and made a selection to see the data.

What return to me in Postman is this:
{
  "title": "CodeIgniter\\Exceptions\\PageNotFoundException",
  "type": "CodeIgniter\\Exceptions\\PageNotFoundException",
  "code": 404,
  "message": "Controller or its method is not found: \\App\\Controllers\\App\\Controllers\\TypeBloodController::index",
  "file": "/home/faker/CodeIgniter/c4/vendor/codeigniter4/framework/system/CodeIgniter.php",
  "line": 988,
  "trace": [
    {
      "file": "/home/faker/CodeIgniter/c4/vendor/codeigniter4/framework/system/CodeIgniter.php",
      "line": 988,
      "function": "forPageNotFound",
      "class": "CodeIgniter\\Exceptions\\PageNotFoundException",
      "type": "::"
    },
    {
      "file": "/home/faker/CodeIgniter/c4/vendor/codeigniter4/framework/system/CodeIgniter.php",
      "line": 370,
      "function": "display404errors",
      "class": "CodeIgniter\\CodeIgniter",
      "type": "->"
    },
    {
      "file": "/home/faker/CodeIgniter/c4/public/index.php",
      "line": 79,
      "function": "run",
      "class": "CodeIgniter\\CodeIgniter",
      "type": "->"
    },
    {
      "file": "/home/faker/CodeIgniter/c4/vendor/codeigniter4/framework/system/Commands/Server/rewrite.php",
      "line": 47,
      "args": [
        "/home/faker/CodeIgniter/c4/public/index.php"
      ],
      "function": "require_once"
    }
  ]
}

Route.php

<?php

use CodeIgniter\Router\RouteCollection;
use App\Controllers\TypeBloodController;

/**
 * @var RouteCollection $routes
 */

$routes->resource('type-blood', ['controller' => TypeBloodController::class]);

$routes->get('/', 'Home::index');

TypeBloodController.php

<?php

namespace App\Controllers;

use App\Controllers\BaseController;
use App\Models\TypeBloodModel;

class TypeBloodController extends BaseController
{
    public function index()
    {
        $type_blood = new TypeBloodModel();
        $datas = $type_blood->findAll();
        $this->response->setContentType('application/json');
        return $this->response->setJSON($datas);
    }

    public function store()
    {
        $type_blood = new TypeBloodModel();
        $validation = $type_blood->getRuleGroup('blood_store');
        $this->response->setContentType('application/json');
        return $this->response->setStatusCode(200)->setJSON(['message' => 'Insertion done.']);
    }

    public function show($id)
    {
        $type_blood = new TypeBloodModel();
        $register = $type_blood->find($id);
        if (!$type_blood) {
            return $this->response->setStatusCode(404)->setJSON(['message' => "Register not found."]);
        }
        $this->response->setContentType('application/json');
        return $this->response->setJSON($register);
    }

    public function update($id)
    {
        $type_blood = new TypeBloodModel();
        $register = $type_blood->find($id);
        if (!$register) {
            return $this->response->setStatusCode(404)->setJSON(['message' => "Register updated."]);
        }
        $validation = $registro->getRuleGroup('blood_update');
        $this->response->setContentType('application/json');
        return $this->response->setJSON($register);
    }

    public function destroy($id)
    {
        $type_blood = new TypeBloodModel();
        $register = $type_blood->find($id);
        if (!$register) {
            return $this->response->setStatusCode(404)->setJSON(['message' => "Register not found"]);
        }
        $register->delete($id);
        $this->response->setContentType('application/json');
        return $this->response->setStatusCode(200)->setJSON(['message' => 'Exclusion done.']);
    }
}


Solution

  • Explanation

    If the controller is provided without a leading backslash (\), the default namespace will be prepended.

    Default Namespace

    When matching a controller to a route, the router will add the default namespace value to the front of the controller specified by the route. By default, this value is App\Controllers.

    Excerpt from CodeIgniter4/app/Config/Routing.php
    class Routing extends BaseRouting
    {
        // ...
        public string $defaultNamespace = 'App\Controllers';
        // ...
    }
    

    If you set the value empty string (''), it leaves each route to specify the fully namespaced controller:

    Solution

    app/Config/Routes.php

    1. Set your default namespace to an empty string (''). I.e: $routes->setDefaultNamespace('');
    2. Convert all your string-based controller syntax to array callable syntax. I.e:
      • Instead of:❌ $routes->get('/', 'Home::index');
      • Use:✅ $routes->get('/', [Home::class, 'index']);
      • The array callable syntax (Since v4.2.0.) also allows for quick navigation to your method or controller when working with an IDE or code editor.

    Example

    <?php
    
    use CodeIgniter\Router\RouteCollection;
    use App\Controllers\TypeBloodController;
    use App\Controllers\Home;
    
    /**
     * @var RouteCollection $routes
     */
    $routes->setDefaultNamespace('');
    
    $routes->get('/', [Home::class, 'index']);
    
    $routes->resource('type-blood', ['controller' => TypeBloodController::class]);