Cornel Verster
Cornel Verster

Reputation: 1781

Limiting retrieved columns when using withPivot on belonsToMany relationship

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

Answers (3)

OMR
OMR

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

D. Petrov
D. Petrov

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

Ali Azimi
Ali Azimi

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

Related Questions