skip to Main Content

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 CodeIgniterRouterRouteCollection;
use AppControllersTypeBloodController;

/**
 * @var RouteCollection $routes
 */

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

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

TypeBloodController.php

<?php

namespace AppControllers;

use AppControllersBaseController;
use AppModelsTypeBloodModel;

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.']);
    }
}

2

Answers


  1. Unfortunately you cannot use a qualified names for specifying the controller option.
    According the documentation it is possible, but it seems to be a minor bug, because in this case it duplicates the namespaces.

    You can always check your routes with the spark command. Check the handler column.

    php spark routes
    

    In my case the handler is: AppControllersAppControllersHome::index, but it should be: AppControllersHome::index

    You can fix it simply:

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

    Note: if your resource and controller names are the same, you can omit the controller option. So you can technically change the name of the controller to TypeBlood and file name to TypeBlood.php. Then simply delete the controller option.

    Note: if your controller is not in the AppControllers namespace, you can specify with the namespace option. For example:

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

    I created a bug issue report, so maybe it will be fixed in the later version.

    Login or Signup to reply.
  2. 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 AppControllers.

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

    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 CodeIgniterRouterRouteCollection;
    use AppControllersTypeBloodController;
    use AppControllersHome;
    
    /**
     * @var RouteCollection $routes
     */
    $routes->setDefaultNamespace('');
    
    $routes->get('/', [Home::class, 'index']);
    
    $routes->resource('type-blood', ['controller' => TypeBloodController::class]);
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search