Reputation: 1781
I have a model called Shifts with a belongsToMany relationship to a shift_employee table that acts as a pivot table to record applications for employees to shifts. I also have a scope so that I can return applications with shift objects. Here is part my Shift model:
class Shift extends Model
{
//
use SoftDeletes;
use \App\Http\Traits\UsesUuid;
protected $guarded = [];
public function applications()
{
return $this->belongsToMany(Employee::class, 'shift_employee')->as('application')->withTimestamps()->withPivot('shortlisted');
}
...
public function scopeWithApplications($query)
{
$query->with('applications');
}
...
}
My shift_employee pivot table is pretty simple and the structure is shown below. I have one extra field to determine if an application has been shortlisted:
Schema::create('shift_employee', function (Blueprint $table) {
$table->primary(['employee_id', 'shift_id']);
$table->uuid('employee_id');
$table->uuid('shift_id');
$table->boolean('shortlisted')->default(false);
$table->timestamps();
$table->foreign('employee_id')
->references('id')
->on('employees');
$table->foreign('shift_id')
->references('id')
->on('shifts')
->onDelete('cascade');
});
Below is my API show function for retrieving shift info:
public function show($id)
{
$shift = Shift::where('id', $id)
->with...()
->withApplications()
->with...()
->first();
return response([
'shift' => $shift,
]);
}
This is the response that I'm getting:
"shift": {
"id": "2b91f55b-c0ff-4bdb-abc4-02604ba6a161",
"some_field": "some_value",
...
"applications": [
{
some_field: "some_value",
...
application: {
shift_id: "2b91f55b-c0ff-4bdb-abc4-02604ba6a161",
employee_id: "some_uuid",
created_at: ...,
updated_at: ...,
shortlisted: 0
}
},
{
...
}
]
...
}
What I want to do, is to replace the whole "application" inner object with only the field "shortlisted" from the pivot table so that it looks like this:
"shift": {
"id": "2b91f55b-c0ff-4bdb-abc4-02604ba6a161",
"some_field": "some_value",
...
"applications": [
{
some_field: "some_value",
...
shortlisted: 0
}
},
{
...
}
]
...
}
How can I do that? Ideally an eloquent call to something like withPivot but that excludes other fields and does not return an object. I couldn't find it in the docs, but does something like that exist?
Upvotes: 1
Views: 269
Reputation: 12188
i think that the most straightforward way is to make independent relation based on the pivot table using pivot model:
class ShiftEmployee extends Pivot
{
protected $table='shift_employee';
}
now the new relation in Shift Model:
class Shift extends Model
{
public function shortlistedApplications()
{
return $this->hasMany(ShiftEmployee::class,'shift_id');
}
public function scopeWithShortlistedApplications($query)
{
$query->with('shortlistedApplications:shift_id,shortlisted');
}
}
now this new scope would bring the data you want
Upvotes: 1
Reputation: 1167
What I think you need is to only load the shortlisted
attribute of your employee's application in your scopeWithApllications
:
public function scopeWithApplications($query)
{
$query->with('applications.application:id,shortlisted');
}
This will still return an Application
instance as a relationship, but will only load it's shortlisted
attribute. Then, after retrieval, you can map your collection in order to merge the application's attribute to your employee, if that's really important. But in terms of data shortage, this will do the trick.
Upvotes: 1
Reputation: 404
In your application model use withPivot method. Like this:
public function applications(){
return $this->belongsToMany('App\Application')
->withPivot('shortlisted')
->withTimestamps();}
You can use this link for more clear example https://laraveldaily.com/pivot-tables-and-many-to-many-relationships/
Upvotes: 0