laravel-json-api / laravel

JSON:API for Laravel applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Controllers cannot be placed in a custom namespace

Azeirah opened this issue · comments

At work, we're working a loosely defined "modular" structure where we try to emulate Laravel packages per feature instead of building everything inside of the standard structure, since we have many many controllers and models and services etc.

While setting up Laravel JSON schema according to the tutorial, everything except controllers can be put inside of the custom namespace. The following is our directory structure

app/
├─ Domains/
│  ├─ Sales/
│  │  ├─ Controllers/
│  │  ├─ Models/
│  │  │  ├─ Policies/
│  │  ├─ JsonApi/
│  │  │  ├─ v1/
│  │  │  │  ├─ SalesSchema.php
│  ├─ Controllers/
├─ Controllers/
│  ├─ AllKindsOfLegacyControllers...
│  ├─ JsonApiUpsellController.php
├─ JsonApi/
│  ├─ Server.php

As you can see, the JsonApiUpsellController is in app/Controllers, but I want it to exist in app/Domains/Sales/Controllers/JsonApiUpsellController.

If I move the file to JsonApi/Controllers, and adjust the namespace import in our api.php file, I get the following error Unable to find \App\Http\Controllers\App\Domains\Controllers\JsonApiUpsellController (paraphrased error, not copy pasted, sorry.)

The imported namespace in routes/api.php is app/Domains/Sales/Controllers/JsonApiUpsellController.

I believe the code is prepending the default Controller namespace to the imported namespace, which is undesired behavior. It should use the exact given namespace, not a namespace it creates itself.

This is not high-prio, but I'm going to come back to this if/when we ever move these domains to actually self-contained Laravel packages and encounter the same issue. It would be nicer if everything could be tightly packed together per-feature/domain instead of per technical implementation.

Hi @Azeirah,

Can you please share (part of) your route file?

I'm actually using controllers in custom folders without any issue. Here's an example of one of how one of my routes look like:

use App\Api\V1\Controllers\RolesController;
use LaravelJsonApi\Laravel\Facades\JsonApiRoute;

JsonApiRoute::server('v1')
    ->prefix('v1')
    ->middleware('auth:sanctum', 'verified')
    ->resources(function ($server) {

        $server
            ->resource('roles', RolesController::class)
            ->readOnly();

    });

Anyway, I'm using the Laravel Json Api package on its 3.0 version on a project that uses Laravel 11, so I'm not sure if this may be working on my setup because the environment is different.

commented

When using Namespace\ClassName instead of \Namespace\ClassName or just ClassName with an use import, the namespaces will add up. More information: https://www.php.net/manual/en/language.namespaces.basics.php

However, it would indeed be nice to have some more code.

My code as-is looks like this. I have an UpsellController in the Upsell Domain like in the directory structure I provided in the original Post

use LaravelJsonApi\Laravel\Routes\ResourceRegistrar;
use LaravelJsonApi\Laravel\Facades\JsonApiRoute;

JsonApiRoute::server('v1'
  ->prefix('v1')
  ->resources(function (ResourceRegistrar $server) {
    $server->resource('upsells', \App\Domains\Upsell\Controllers\UpsellController::class)->readOnly();
  });

It doesn't matter if I move the namespace up to a "use" statement like the two imports above, same error.

Target class [App\\Http\\Controllers\\App\\Domains\\Upsell\\Controllers\\UpsellController] does not exist.

You can put your controllers anywhere. This package isn't doing anything "special" with controllers - it's using standard Laravel router functionality. I.e. the controller is just passed through to the Laravel router. Our routing classes are just effectively "wrappers" that call standard Laravel functionality underneath.

Have you checked the docs here?
https://laraveljsonapi.io/docs/3.0/routing/#controllers-and-namespaces

There is some difference in how your application can be set up, particularly if it was created before Laravel 8. That's explained in that section of the docs.

You can put your controllers anywhere. This package isn't doing anything "special" with controllers - it's using standard Laravel router functionality. I.e. the controller is just passed through to the Laravel router. Our routing classes are just effectively "wrappers" that call standard Laravel functionality underneath.

Have you checked the docs here? https://laraveljsonapi.io/docs/3.0/routing/#controllers-and-namespaces

There is some difference in how your application can be set up, particularly if it was created before Laravel 8. That's explained in that section of the docs.

This is the answer, thank you. The application was indeed created before Laravel 8.