lepikhinb / laravel-fluent

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error : Typed property App\Models\User::$name must not be accessed before initialization

milewski opened this issue · comments

Hi, I have a very simple example like this:

class User extends Model
{
    use Fluent;

    public string $name;
}

Within tests:

$user = UserFactory::new()->create();
dd($user->name);

Throws an error:

Error : Typed property App\Models\User::$name must not be accessed before initialization

What Laravel version is being used? I just tried the same example, and it worked as expected.

I'm having the same problem.
Versions:
PHP: 8.0.10
laravel/framework: v8.61.0


Edit:

I only get the error when the model has a relation.
I tested it with the following code, and it gave the error:

// database/migrations/2021_09_14_184632_create_cars_table.php
Schema::create('cars', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id');
    $table->timestamps();

    $table->foreign('user_id')->references('id')->on('users');
});
// app/Models/Car.php
namespace App\Models;

use Based\Fluent\Fluent;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Car extends Model
{
    use Fluent;

    public int $user_id;

    public User $user;

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
// php artisan tinker
>>> \App\Models\User::factory(1)->create()
>>> $car = new \App\Models\Car
>>> $car->user_id = \App\Models\User::find(1)->id
>>> $car->save()
>>> $car2 = \App\Models\Car::find(1)
>>> $car2->user
PHP Error:  Typed property App\Models\Car::$user must not be accessed before initialization in Psy Shell code on line 1

@milewski

I can only reproduce this by setting name to nullable and removing the name from the factory.
Do you have any other package that can conflict with this one?
Perhaps, do you have a reproducible example?

@devRMA

I can reproduce this one, but loading the relation instead of lazyloading works.

$car2 = \App\Models\Car::find(1)
$car2->load('user')->user;

// or
$car2 = \App\Models\Car::with('user')->find(1)
$car2->user;

I think, this makes sense since user is not initialized at this moment and needs to be initialized at some point before you can actually call the property. But that just how PHP works. I'm unsure Fluent can be compatible with LazyLoading.

Uhm I was using this package https://github.com/spatie/data-transfer-object as well when this happened, I will try to hook up this library again on some other project and see if I can find out what is wrong

@devRMA The package doesn't support lazy loading. Unfortunately, there's no way to overload public properties by magic getters and setters, so we can't access relations directly unless they're loaded explicitly.

@milewski Let me know if the issue was resolved. Otherwise, I would love to see a more detailed example.

@devRMA The package doesn't support lazy loading. Unfortunately, there's no way to overload public properties by magic getters and setters, so we can't access relations directly unless they're loaded explicitly.

Thanks for the answer. I think this should be in the README, which only works with eager loading.

@devRMA will note this on README. Thanks!

FYI @lepikhinb this was not noted on README.

It's a huge drawback as MyModel::find(1) is no longer a valid way of doing things.