krecebli's avatar

New attribute casting and relationships

Well, let's say I have a relationship:

public function file(): HasOne
{
    return $this->hasOne(File::class, 'id', 'file_id');
}

But I also need a setter for file. In Laravel 8 and below I did it like this:

public function setFileAttribute(array $value = null): void
{
    $this->attributes['file_id'] = $value ? $value['id'] : null;
}

Now it looks like this:

public function setFileAttribute(array $value = null): void
{
    $this->attributes['file_id'] = $value['id'] ?? null;
}

Yeah, not so much difference :) But I want to completely remove this and use new attribute casting, but how to do it? I tried something like this:

public function file(): Attribute
{
    return Attribute::make(
        get: fn (): HasOne => $this->hasOne(File::class, 'id', 'file_id'),
        set: fn (array $value = null): array => [
            'file_id' => $value['id'] ?? null,
        ]
    );
}

But it doesn't work. Any idea how to implement this?

0 likes
3 replies
tykus's avatar

Don't mix relationships and Attributes; in fact, better if you don't name an Attribute/Mutator the same as your relationship name!

krecebli's avatar

@tykus but there's no other suitable name for them. With setFileAttribute there wasn't any name collision. I could easily make dump($post->file) and $post->update(['file' => ['id' => 1]]) without any issue. But by switching to public function file(): Attribute I can't use relationship public function file(): HasOne, and vice versa. Because it's impossible to overload method like in C++.

Please or to participate in this conversation.