Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

maatata's avatar

Laravel nested route without having parent parameter

I'm trying to work out how I can achieve this with Laravel route and controller. I'm having 3 tables as below:

user

  • id
  • name
  • company

company

  • name
  • company_user

company_user

  • user_id
  • company_id

So as you might have guessed I have the following models:

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    public function companies(): BelongsToMany
    {
        return $this->belongsToMany(Company::class);
    }
}
class Company extends Model
{
    use HasFactory, SoftDeletes;

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }
}

The relationship is ManyToMany and it works all fine.

So I'm trying to achieve the following route:

Route::apiResource('company/user', CompanyUserController::class);

I know I can achieve such this by the following route easily:

Route::apiResource('company.user', CompanyUserController::class);

However what I need in my route is not to require to pass the company id as route parameter.

I want the company_id to be set automatically through payload from JWT token which I already have. So imagine we have company_id as 1 in JWT token payload and I want the user to go to this link: GET /company/user and controller would then list all users who belong to the company_id 1 which is grabbed from logged in user JWT token payload. I want the nested resource functionality without needing to pass the parent parameter in the route and instead grabbing it automatically from logged in user token.

I don't want the route to be like /company/1/user.

I hope someone could help me achieve such these. This also needs to apply to all other controller methods automatically as in show, store, update etc.

Thanks guys.

0 likes
10 replies
vincent15000's avatar

According to your tables, a user can belong to multiple companies.

If a user is attached to multiple companies, you cannot choose which company_id to send to the front, you must send all the companies ids to which the connected use is attached.

Then I would rather have these table fields instead of yours.

users
- id
- name

companies
- id
- name

company_user
user_id
company_id

And you can retrieve the companies ids like this.

$companiesIds = auth()->user()->companies->pluck('id')->toArray();

But if it's a mistake and each use is attached only to one company, it's different. Then the tables should be like these.

users
- id
- name
- company_id

companies
- id
- name

And then you can retrieve the company id when you need just via the connected user (no need to add it to the payload).

auth()->user()->company_id
krisi_gjika's avatar

@vincent15000 this loads all companies and than it plucks using collections:

$companiesIds = auth()->user()->companies->pluck('id')->toArray();

instead do:

$companiesIds = auth()->user()->companies()->pluck('id')->toArray();
1 like
vincent15000's avatar

@krisi_gjika I don't agree with you, my suggestion works fine, I use it regularly.

auth()->user()->companies returns a collection of companies and the pluck() helper can be applied to a collection.

When you add (), you retrieve a query and then you can apply the pluck() method on the query to retrieve a collection of the column specified as a parameter of the method.

So both work ;).

1 like
krisi_gjika's avatar

@vincent15000 I agree they both work, that's not what I meant. And if a user can have 2 or 3 companies the difference is not work discussing. However if a user can have hundreds of companies the first method can lead to issues. Just though to make that difference clear for anyone who might see this in the future.

maatata's avatar

Hi @vincent15000 and @krisi_gjika

Thanks for your reply. But unfortunately none of you have answered my question.

I don't have any problem with relationships and that's all working fine.

My question is about route and controller.

Thanks.

Snapey's avatar

perhaps api user resource inside route group with prefix of 'company'

maatata's avatar
maatata
OP
Best Answer
Level 1

Thanks all for contribution. Thank you @snapey for the hint.

Just to answer my own question, I ended up doing this route:

Route::apiResource('company/user', CompanyUserController::class); As @snapey suggested.

Then I did the following in my CompanyUserController constructor to make sure I'm sanitising data before hitting the methods.

public function __construct()
    {
        $payload = auth()->payload();
        $companyId = $payload->get('companyId');
        // making sure the selected company exists
        try {
            $this->company = Company::where('id', $companyId)->firstOrFail();
        } catch (ModelNotFoundException $exception) {
            abort(Response::HTTP_NOT_FOUND, "Unable to find company");
        }

        // making sure the logged in user is part of the selected company
        try {
            $this->company->users()->where('users.id', Auth::user()->id)->firstOrFail();
        } catch (ModelNotFoundException $exception) {
            abort(Response::HTTP_NOT_FOUND, "You don't belong to this company.");
        }
    }
maatata's avatar

@vincent15000 Because @snapey did not say anything about how to handle the checks on making sure the company and users are actually linked. He just offered a route.

Snapey's avatar

I didn't suggest the way you did it either.

My checks (if asked) would be like;

abort_unless(
	$this->company = Company::find($payload->get('companyId'))   &&
	$this->company->users()->where('id',Auth::id())->exists(), 404);


Please or to participate in this conversation.