Skip to content

[12.x] Add Eloquent Relationship Attributes #56415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

WendellAdriel
Copy link
Contributor

Overview

Since Laravel has been embracing the usage of Attributes, this PR introduces 12 new attributes for defining relationships in the Eloquent Models.

Why

Right now, we use methods in Model classes to define relationships. But this can lead to a mix of methods like relationships, scopes, and mutators mixed inside the class. By using Attributes, we group all relationship definitions in one place in the class. This makes it easier to see all the relations for a model at once.

Examples

These attributes work just like methods. You pass the arguments in the same order. Here are some examples from the test cases in this PR.

#[BelongsTo(BookCase::class)]
#[HasMany(Price::class, null, 'custom_id', 'id')]
class Book extends Model {}

#[HasMany(Book::class)]
class BookCase extends Model {}

#[HasOne(Manufacturer::class)]
class Computer extends Model {}

#[HasMany(User::class)]
#[HasManyThrough(Post::class, User::class)]
class Country extends Model {}

#[MorphTo('imageable')]
class Image extends Model {}

#[HasMany(LibraryBook::class)]
class Library extends Model {}

#[BelongsTo(Library::class)]
class LibraryBook extends Book {}

class Manufacturer extends Model {}

#[BelongsTo(User::class)]
class Phone extends Model {}

#[BelongsTo(related: User::class, name: 'author')]
#[MorphMany(Image::class, 'imageable')]
#[MorphToMany(Tag::class, 'taggable')]
class Post extends Model {}

#[BelongsTo(Book::class, null, 'custom_id', 'id')]
class Price extends Model {}

#[BelongsToMany(User::class)]
class Role extends Model {}

#[HasOneThrough(Manufacturer::class, Computer::class)]
#[HasOne(Computer::class)]
class Seller extends Model {}

#[MorphedByMany(Post::class, 'taggable')]
class Tag extends Model {}

#[BelongsToMany(related: Role::class, name: 'roleList')]
#[HasMany(related: Post::class, name: 'articles')]
#[HasMany(WorkBook::class)]
#[HasOne(Phone::class)]
#[MorphOne(Image::class, 'imageable')]
class User extends Model {}

#[BelongsTo(User::class)]
final class WorkBook extends Book {}

@taylorotwell taylorotwell marked this pull request as draft July 25, 2025 14:46
@ludo237
Copy link

ludo237 commented Jul 25, 2025

This reminds me of Doctrine, which I don't know if it's good or bad 😅 this implementation assumes that the method is called like the relationship by default and use the $name property to overwrite it, right?

@WendellAdriel
Copy link
Contributor Author

This reminds me of Doctrine, which I don't know if it's good or bad 😅 this implementation assumes that the method is called like the relationship by default and use the $name property to overwrite it, right?

It assumes the conventional naming for the relationship, like between User and Post would be

$user->posts;
$post->user;

@WendellAdriel
Copy link
Contributor Author

Hey there @taylorotwell, sorry to bother by mentioning you. I just wanted to check if I should change anything on this solution. I saw it was marked as a draft, but IDK if I should update it somehow. Thanks in advance.

@shaedrich
Copy link
Contributor

shaedrich commented Aug 3, 2025

This reminds me of Doctrine, which I don't know if it's good or bad 😅 this implementation assumes that the method is called like the relationship by default and use the $name property to overwrite it, right?

It assumes the conventional naming for the relationship, like between User and Post would be

$user->posts;
$post->user;

@ludo237 But it looks like this is customizable via the $name argument if I'm not mistaken

@ludo237
Copy link

ludo237 commented Aug 3, 2025

This reminds me of Doctrine, which I don't know if it's good or bad 😅 this implementation assumes that the method is called like the relationship by default and use the $name property to overwrite it, right?

It assumes the conventional naming for the relationship, like between User and Post would be

$user->posts;
$post->user;

@ludo237 But it looks like this is customizable via the $name argument if I'm not mistaken

Yes it is

@WendellAdriel
Copy link
Contributor Author

Hey there @taylorotwell, sorry to bother by mentioning you. I just wanted to check if I should change anything on this solution. I saw it was marked as a draft, but IDK if I should update it somehow. Thanks in advance.

A follow-up on this.
@taylorotwell I'm marking this as ready to review again. If changes are needed, please let me know.

@WendellAdriel WendellAdriel marked this pull request as ready for review August 5, 2025 11:28
@taylorotwell
Copy link
Member

Thanks for your pull request to Laravel!

Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include.

If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants