skip to Main Content

I am developing a sort of multi-tenant application with Laravel 11 on PHP 8.3, where each "user" must belong to a "company".

For user management, I started from Laravel Breeze, and then modified the users table to include a company_id which references companies:

Schema::create("users", function (Blueprint $table) {
    ...
    $table->foreignUuid("company_id")->constrained();
    ...
});

Then I defined the relation in the model:

public function company(): BelongsTo {
    return $this->belongsTo(Company::class);
}

The problem is, if in the controller I try to access $request->user()->company it comes out as null; the same happens if I try to access it with $request->user()->company()->first().

However, if I try with artisan tinker, I see it works properly:

$ php artisan tinker
Psy Shell v0.12.4 (PHP 8.3.8 — cli) by Justin Hileman
> $user = User::where('email', '[email protected]')->firstOrFail();
[!] Aliasing 'User' to 'AppModelsUser' for this Tinker session.
= AppModelsUser {#6215
    id: "9c549870-805a-4555-bd72-86ba982a3c04",
    company_id: "9c54986f-8284-4da9-b826-c7a723de279b",
    name: "TEST test",
    email: "[email protected]",
    email_verified_at: "2024-06-20 08:18:06",
    #password: "$2y$12$wboWRmK/9B5uOT28.u/BO..gIlY0Sz75l7kQL8eIGBdRcxB5dGSn2",
    #remember_token: null,
    created_at: "2024-06-20 08:18:06",
    updated_at: "2024-06-20 08:18:06",
    deleted_at: null,
  }

> $user->company;
= AppModelsCompany {#6248
    id: "9c54986f-8284-4da9-b826-c7a723de279b",
    name: "TEST Administration",
    is_master: 1,
    fiscal_id: null,
    email: null,
    phone: null,
    mobile: null,
    address_line_1: null,
    address_line_2: null,
    address_post_code: null,
    address_city: null,
    address_province: null,
    created_at: "2024-06-20 08:18:06",
    updated_at: "2024-06-20 08:18:06",
    deleted_at: null,
  }

I have found this previous question, where a comment suggests to preload the relationship by modifying the user model by adding:

protected $with = ['company'];

I tried it, and it seems to work, however it does not seem right to have to eager load it each time, even when it is not needed (the majority of cases).

How can I have the relationships work when accessing the user with $request->user() without preloading them?

I have seen that it does not work even if I try to refresh() the entity, or to manually load() the relation; however, $user->company_id is correctly set and $company = Company::find($user->company_id) works, but I really do not see why I cannot use the declared relationship.

2

Answers


  1. Chosen as BEST ANSWER

    In the end, I found out that the problem was caused by a global scope applied to the "company" model.

    In fact, I have created a global scope that, if there is a logged user and that user does not have a specific authorization, applies a condition on the company_id of the entities which the application is querying.

    However, it was applied to the Company model too, and in that case, the implementation was wrong, as the table does not contain a company_id field (it has an id), and it generated the wrong query:

    select * from "companies" where "companies"."id" = '9c54986f-8284-4da9-b826-c7a723de279b' and "companies"."deleted_at" is null and "company_id" = '9c54986f-8284-4da9-b826-c7a723de279b'
    

    I fixed the global scope implementation to use the correct field in this case, and it now works.

    The problem is that the query as generated fails (as in, it does not found any record) but does not seem to generate an error when using SQLite.


  2. you can do like

    User::with('relationship')->get();
    

    or

    $user->load('relationship')
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search