Skip to content
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

[5.6] Default attributes for pivot table during fetching and creating rows #22867

Merged
merged 7 commits into from Jan 23, 2018
Merged

Conversation

sikhlana
Copy link
Contributor

As per the proposal: laravel/ideas#872.

Added a new method so that default pivot values can be set during fetching and creating rows.
This version also includes tests.

@taylorotwell
Copy link
Member

This needs a thorough explanation, demonstration of the new features, explanation of benefit to users, etc.

@sikhlana
Copy link
Contributor Author

sikhlana commented Jan 21, 2018

For example, in this kind of many-to-many relationship:

users:
    - id
    ...

clubs:
    - id
    ...

club_user:
    - club_id
    - user_id
    - role

With the Club model having these belongsToMany relationships defined:

public function members()
{
    return $this->belongsToMany(User::class);
}

public function admins()
{
    return $this->belongsToMany(User::class)->wherePivot('role', 'admin');
}

public function staff()
{
    return $this->belongsToMany(User::class)->wherePivot('role', 'staff');
}

If you want to attach a new administrator for the club, something like:

$club->admins()->attach(1);

won't work, but rather:

$club->admins()->attach(1, ['role' => 'admin']);
OR
$club->members()->attach(1, ['role' => 'admin']);
OR
$club->staff()->attach(1, ['role' => 'admin']);

All of these work, but is counter intuitive and some might get confused as to what is happening here since to add an administrator, calling $club->admins()->attach(1) would have sufficed.

This is where this PR comes in play with the new withPivotValues() method:

public function members()
{
    return $this->belongsToMany(User::class);
}

public function admins()
{
    return $this->belongsToMany(User::class)->withPivotValues('role', 'admin');
}

public function staff()
{
    return $this->belongsToMany(User::class)->withPivotValues('role', 'staff');
}

Which extends the wherePivot() method and caches the values used, to pass them on as base attributes when a new pivot row is created.

This would allow the devs to write less in these kind of situations and the syntax is easily understandable.

@GrahamCampbell GrahamCampbell changed the title Default attributes for pivot table during fetching and creating rows. [5.6] Default attributes for pivot table during fetching and creating rows. Jan 21, 2018
@jmarcher
Copy link
Contributor

This could be solved with polymorphisms or am I missing something?

@sikhlana
Copy link
Contributor Author

@jmarcher polymorphic relationship allows the inclusion of different "content types" in a single table. This PR is to do with different default values and conditions for the same pivot table to create different relationships.

@taylorotwell
Copy link
Member

@jmarcher do you have an example of how you would solve this? Not quite sure what you mean.

@taylorotwell taylorotwell merged commit fcbc5d6 into laravel:5.6 Jan 23, 2018
@Stalinko
Copy link

Pretty weird way to set default attributes, don't you find that?

The only option now to set the default attributes on a Pivot is call withPivotValues() which will automatically add where filters, but what to do if I don't need the filters but want to specify default attributes nevertheless? It would be super convenient and consistent to have $attributes property in Pivots working the same way as in Models.

@sikhlana
Copy link
Contributor Author

@Stalinko not really. It may be highly opinionated, but why define default attributes for a pivot row if that is not going to be used as a filter?

@Stalinko
Copy link

@sikhlana well there can be various situations.

Let's consider the example above with "club members". Imagine you decide to add a new attribute membership_status. All existing and new members will receive "bronze" status by default.

How to implement this default value without filters (hence withPivotValues() won't work) using only existing laravel features? There is no solution at the moment. You'll have to write some custom code or set this default value everywhere manually.
The simplest option of course would be to specify the default value in DB but it won't be available in the code until you reload the model from DB, so it's not ideal too.

@sikhlana
Copy link
Contributor Author

@Stalinko yeah true, that makes sense. I always go with factory classes for this kinda situation, but then again that's a custom solution. There can be a better solution for this.

@Stalinko
Copy link

@sikhlana yep! When I faced a similar situation I read about default attributes in Eloquent (https://laravel.com/docs/5.8/eloquent#default-attribute-values) and was 100% sure it would work in Pivot the same way (basically because Pivot inherits from Model). But it didn't.

@rdcx
Copy link

rdcx commented Jul 16, 2020

Is withPivotValues not available in "^7.0" ?

@BrandonSurowiec
Copy link
Contributor

@rdcx It is singular, not plural: withPivotValue($column, $value = null)

@lucianholt97
Copy link

Is there some way to add a pivotValue without adding a wherePivot?
The use case is as follows: I have a nullable tenant column and users may get rows with their tenant or with tenant = null. This column is on a pivot table which I can't access directly. When a new relation is added, I would like to fill the tenant by default via withPivotValue.
The problem is that withPivotValue adds a wherePivot which I need to neutralize with a orWherePivotNull. Since I cannot encapsulate pivot wheres I run into the following issue: #29741.

It would be really easy to add a third argument to withPivotValue which enabled a mode where no wherePivot is applied. Alternatively you could easily make protected $pivotValues public, so I can access it directly.
Thanks in advance!

@GrahamCampbell GrahamCampbell changed the title [5.6] Default attributes for pivot table during fetching and creating rows. [5.6] Default attributes for pivot table during fetching and creating rows Jan 1, 2021
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.

None yet

7 participants