laraveleloquenteloquent-relationshiplaravel-eloquent-resource

Laravel Check for Value from Relation


I have a query that looks like this where I fetch data for various businesses in a particular location and I need to be able to tell that each business has (or does not have) a female employee.

    $business = Business::where('location', $location)
        ->with(['staff'])
        ->get();


        return MiniResource::collection($business);

My Mini Resource looks like this:

    return [
        'name' => $this->name,
        'location' => $this->location,
        'staff' => PersonResource::collection($this->whenLoaded('staff')),
    ];

This is what a sample response looks like:

{
  "id": 1,
  "name": "XYZ Business"
  "location": "London",
  "staff": [
    {
      "name": "Abigail",
      "gender": "f",
      "image": "https://s3.amazonaws.com/xxxx/people/xxxx.png",
      "role": "Project Manager",
    },
    {
      "name": "Ben",
      "gender": "m",
      "image": "https://s3.amazonaws.com/xxxx/people/xxxx.png",
      "role": "Chef",
    },
  ]
}

I really don't need the staff array, I just want to check that a female exists in the relation and then return something similar to this:

{
  "id": 1,
  "name": "XYZ Business"
  "country": "USA",
  "has_female_employee": true;
}

Is there an eloquent way to achieve this ?

NB: In my original code I have more relations that I query but I had to limit this post to be within the scope of my problem.


Solution

  • If you are only looking for male or female staff members, you can achieve it like so:

    $someQuery->whereHas('staff', function ($query) {
        $query->where('gender', 'f');
    })
    

    If you want both genders, I wouldn't go through the hassle of achieving this in the query, but recommend reducing your results collection in your MiniResource:

    return [
        'name' => $this->name,
        'location' => $this->location,
        'has_female_employee' => $this->whenLoaded('staff')->reduce(
            function ($hasFemale, $employee) {
                $hasFemale = $hasFemale || ($employee->gender === 'f'); 
                return $hasFemale;
            }, false),
    ];
    

    Even better would be to create it as a method on your MiniResource for readability.