1

I've got a problem with relations in Laravel 9.14 Eloquent.

I have two models File and Project with coresponding tables in MySql database files and projects.

Project migration

Schema::create('projects', static function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('code');
        $table->string('theme');
        $table->foreignId('discipline_id')->constrained('disciplines');
        $table->foreignId('user_id')->constrained('users');
        $table->string('external_id');
        $table->foreignId('preview')->nullable()->constrained('files');
        $table->date('publish_date');
        $table->timestamps();
    });

File migration

Schema::create('files', static function (Blueprint $table) {
        $table->id();
        $table->string('original_name');
        $table->string('extension');
        $table->string('mime_type');
        $table->integer('size')->unsigned();
        $table->timestamps();
    });

Project has field which is related to the File model called 'preview'. Project, basically can have only one preview file. So I did these relatioins in models:

class Project extends Model


public function preview(): BelongsTo
{
    return $this->belongsTo(File::class, 'preview', 'id');
}

class File extends Model

public function previewProject(): HasOne
{
    return $this->hasOne(Project::class, 'preview', 'id');
}

When i try to get preview of a project this way (controller method):

public function index(): Factory|View|Application
{
    $userId = auth()->user()->id;
    $projects = User::find($userId)->projects()->with(['user', 'preview'])->get();

    //dd($projects->first()->user);
    ddd($projects->first()->preview);

    return view('user.index', [
        'projects' => $projects
    ]);
}

Instead of File model object I get only integer id of File. Queries, however, look right:

queries image

What is the problem here?

halfer
  • 19,824
  • 17
  • 99
  • 186
Lazzytchik
  • 13
  • 3
  • May be intended by framework to save performance. Lazy loading can load data when needed. – Markus Zeller Jun 08 '22 at 14:52
  • So what does the `dd()` show? Also, you don't need to do a database lookup to get a user you already have. `auth()->user()->projects...` – miken32 Jun 08 '22 at 14:58
  • @MarkusZeller, maybe, but query proceed. It doesn't look like right case here. – Lazzytchik Jun 08 '22 at 15:04
  • @miken32, dd() shows single integer of 1. Thanks on the advice for optimization. – Lazzytchik Jun 08 '22 at 15:06
  • Oh I see the problem; your database column name is the same as the relationship name. Your column should really be called `file_id` to stick with Laravel conventions. – miken32 Jun 08 '22 at 15:08
  • @miken32, is that a problem? I mean can i avoid this convention? – Lazzytchik Jun 08 '22 at 15:11
  • You can, but you're finding out why it's a bad idea. Just don't name your relationship the same as a database column. – miken32 Jun 08 '22 at 15:13
  • @miken32, i dont want to name it like file_id since ill have more relations with files table in futher development, so ill have to name columns differently anyway. If there is a way to stick with custom name for column, can I have a clue? :) – Lazzytchik Jun 08 '22 at 15:16
  • Like I said, just don't give your relationship the same name as a database column. – miken32 Jun 08 '22 at 15:17
  • @Lazzytchik you can name it `preview_id` since that what it is, instead of `preview` – N69S Jun 08 '22 at 15:17

1 Answers1

0

There is no error, the integer your are getting is the value of the attribute but by "chance" both your attribute and relation have the same name.

Either change the relation name:

class Project extends Model

public function previewFile(): BelongsTo
{
    return $this->belongsTo(File::class, 'preview', 'id');
}
public function index(): Factory|View|Application
{
    $projects = auth()->user()->projects()->with(['user', 'previewFile'])->get();

    //dd($projects->first()->user);
    ddd($projects->first()->previewFile);

    return view('user.index', [
        'projects' => $projects
    ]);
}

Or change the attribute name

Schema::create('projects', static function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('code');
        $table->string('theme');
        $table->foreignId('discipline_id')->constrained('disciplines');
        $table->foreignId('user_id')->constrained('users');
        $table->string('external_id');
        $table->foreignId('preview_id')->nullable()->constrained('files');
        $table->date('publish_date');
        $table->timestamps();
    });
class Project extends Model

public function preview(): BelongsTo
{
    return $this->belongsTo(File::class, 'preview_id', 'id');
}
N69S
  • 16,110
  • 3
  • 22
  • 36