Mark Redfern
Mark Redfern

Reputation: 507

Manipulate Eloquent object after query

I currently have a shocking schema which I have inherited and due to eloquent not being able to filter against joined models I need to apply some filtering to the returned model + related models. Basically I have a movie object, which has a collection of malls where the movie is currently showing. I need to filter that collection where the "endDate" is >= today. No matter how I try and do this the model never seems to change. I can successfully filter the collection using array_filter, but I cannot assign it back to the model in any way? I return the whole model as a json object in a web service ( Response::json... )

I just want to know if this is at all possible or if i should bark up another tree? Here is a sample of the json data returned

{
"error": false,
"message": "Success",
"data": {
    "movieID": "####",
    "name": "The Grand Seduction",
    "description": "The residents of a once-thriving Newfoundland coastal town are having trouble finding a way to make a living since the collapse of the fishing industry. They're thrilled when a plastics manufacturer proposes to set up shop until they find out the contract requires a resident doctor. \r\n\r\nThe villagers decide to woo Dr. Lewis (Taylor Kitsch), an ethically suspect cosmetic surgeon temporarily banished to the physician-starved seaside. Without revealing their plan, they take up the doctor's beloved sport of cricket, falling all over themselves in an effort to persuade him that their sleepy hamlet is loaded with cosmopolitan sophistication.",
    "smallImage": "grand_seduction_small.jpg",
    "length": "TBA",
    "cast": "Anna Hopkins,BRENDAN GLEESON,Gordon Pinsent,Liane Balaban,Mark Critch,Matt Watts,Taylor Kitsch",
    "director": "Don McKellar",
    "producer": "Barbara Doran,Roger Frappier",
    "ageRestriction": "TBA",
    "genre": "Comedy",
    "linkToSite": "",
    "display": "Y",
    "bigImage": "grand_seduction_large.jpg",
    "threeD": "N",
    "dateAdded": "2014-09-16 23:59:59",
    "largeImage": "",
    "YouTubeID": "",
    "whatsshowing": [
        {
            "whatsShowingID": "####",
            "mallID": "###",
            "startDate": "2014-12-06 00:00:00",
            "endDate": "2014-12-06 23:59:59",
            "pivot": {
                "movieID": "####",
                "whatsShowingID": "#####",
                "times": "09:00; 11:30; 14:00; 22:45; ",
                "featured": "",
                "finalWeek": "N"
            }
        },
        {
            "whatsShowingID": "####",
            "mallID": "###",
            "startDate": "2014-11-29 00:00:00",
            "endDate": "2014-11-29 23:59:59",
            "pivot": {
                "movieID": "####",
                "whatsShowingID": "####",
                "times": "09:00; 14:15; 19:30; ",
                "featured": "",
                "finalWeek": "N"
            }
        },...........

As you can see, I get back 1 movie and then a collection of "whatsshowing" objects and would like to remove any of them that have an endDate less than today.

Here is a snippet of controller code to explain what I am doing currently

$query = MovieModel::query();
$query = $query->with('whatsshowing');
$data = $query->findOrFail($id);
//filter out what I dont want
$new = array_filter($data->whatsshowing->toArray(), function($obj){
    if (isset($obj["endDate"])) {
        if ($obj["endDate"] >= '2014-12-14')
            return true;
    }
    return false;
});
//assign the data back to the object
data->whatsshowing = $new;
//?????? nothing changes??

Could it be that the property is protected? I haven't a clue and am ready to throw this pc through the wall...

Please bear in mind I am a C# developer with a grand total of 4 months PHP experience so please be gentle...

Upvotes: 1

Views: 1018

Answers (2)

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81167

eloquent not being able to filter against joined models - this is basically wrong.

You want eager load constraints:

MovieModel::with(['whatsshowing' => function ($q) {
  $q->where('endDate', '>=', DB::raw('curdate()'));
}])->findOrFail($id);

Obviously DB::raw('curdate()') piece can be replaced with eg. Carbon::today(), date('Y-m-d') and so on.

Upvotes: 2

lukasgeiter
lukasgeiter

Reputation: 152890

Solution

$data->setRelation('whatsshowing', $new);

However $new needs to be a Collection, so do this:

$new = $data->whatsshowing->filter(function($obj){
    if($obj->endDate >= '2014-12-14'){
       return true;
    }
    return false;
});
$data->setRelation('whatsshowing', $new);

Explanation

The problem is, the relations of results are stored inside a relations array on the model (and not just as properties). When you call Response::json (resulting in ->toJson() on the model), Laravel ignores the property you added and uses the value from relations[].

What setRelation() does? It just stores the value inside the relations array.

Upvotes: 0

Related Questions