alexw
alexw

Reputation: 8668

Modifying the collection of related models after executing query

I've loaded a model along with a belongsToMany relationship from my database:

$author = Author::with('publications')->first();

/** Returns something like:

{
    "id": 3457,
    "email": "[email protected]",
    "publications": {
        "1": {
            "id": 240897,
            "title": "Food left by other people at a restaurant - is it safe to eat?  A comparative review.",
            "journal": "Journal of Scrounging and Gleaning",
            "year": 2007,
            "pivot": {
                "author_id": 3457,
                "publication_id": 240897
            }
        },
        "2": {
            "id": 249196,
            "title": "Stop picking at it - you'll leave a scar!",
            "journal": "Proceedings of the International Conference on Nagging",
            "year": 2008,
            "pivot": {
                "author_id": 3457,
                "publication_id": 249196
            }
        }
    }
}

*/

I then fetch some additional data for each publication from a third-party API and merge it into my collection, which works fine.

However, I then want to sort the publications based on this third-party data, so I use a callback in sortByDesc:

$sorted = $author->publications->sortByDesc(function ($publication, $key) {
    // Blah blah blah not important how I sort
    return $blah;
});

$author->publications = $sorted->values();

According to the docs for sortBy, I need to use values if I want to renumber my results after sorting. $sorted->values() does indeed seem to be a re-keyed, sorted list, but even after I assign it to $author->publications, $author->publications still has the old keys.

Even more strange is that just running sortByDesc seems to sort the list in-place, even if I don't assign the result back to $author->publications. Why can't I assign my re-keyed collection back to $author->publications? I have a feeling that this has something to do with the nuances of relations versus attributes, but I don't know how to address this.

Upvotes: 0

Views: 52

Answers (1)

alexw
alexw

Reputation: 8668

The problem is that when I assign the sorted collection to $author->publication, I'm not actually overwriting the relation $author->publication. Rather, I'm just adding a new attribute to $author which also happens to be called publication. Thus, my $author object ends up looking something like this:

UserFrosting\Author Object
(
    [timestamps] => 
    [connection:protected] => 
    [table:protected] => author
    [primaryKey:protected] => id
    [perPage:protected] => 15
    [incrementing] => 1
    [attributes:protected] => Array
        (
            [id] => 3457
            [email] => [email protected]
            [publications] => Illuminate\Database\Eloquent\Collection Object
                (
                    [items:protected] => Array
                        (
                            [0] => UserFrosting\Publication Object
                                (
                                    [timestamps] => 
                                    [connection:protected] => 
                                    [table:protected] => publication
                                    [primaryKey:protected] => id
                                    [perPage:protected] => 15
                                    [incrementing] => 1
                                    [attributes:protected] => Array
                                        (
                                            [id] => 240897
                                            [title] => Food left by other people at a restaurant - is it safe to eat?  A comparative review.
                                            [journal] => Journal of Scrounging and Gleaning
                                            [year] => 2007
                                        )
                                )
                            [1] => UserFrosting\Publication Object
                                (
                                    [timestamps] => 
                                    [connection:protected] => 
                                    [table:protected] => publication
                                    [primaryKey:protected] => id
                                    [perPage:protected] => 15
                                    [incrementing] => 1
                                    [attributes:protected] => Array
                                        (
                                            [id] => 249196
                                            [title] => Stop picking at it - you'll leave a scar!
                                            [journal] => Proceedings of the International Conference on Nagging
                                            [year] => 2008
                                        )
                                )                                
                        )
                )
        )

    [relations:protected] => Array
        (
            [publications] => Illuminate\Database\Eloquent\Collection Object
                (
                    [items:protected] => Array
                        (
                            [1] => UserFrosting\Publication Object
                                (
                                    [timestamps] => 
                                    [connection:protected] => 
                                    [table:protected] => publication
                                    [primaryKey:protected] => id
                                    [perPage:protected] => 15
                                    [incrementing] => 1
                                    [attributes:protected] => Array
                                        (
                                            [id] => 240897
                                            [title] => Food left by other people at a restaurant - is it safe to eat?  A comparative review.
                                            [journal] => Journal of Scrounging and Gleaning
                                            [year] => 2007
                                        )
                                )
                            [0] => UserFrosting\Publication Object
                                (
                                    [timestamps] => 
                                    [connection:protected] => 
                                    [table:protected] => publication
                                    [primaryKey:protected] => id
                                    [perPage:protected] => 15
                                    [incrementing] => 1
                                    [attributes:protected] => Array
                                        (
                                            [id] => 249196
                                            [title] => Stop picking at it - you'll leave a scar!
                                            [journal] => Proceedings of the International Conference on Nagging
                                            [year] => 2008
                                        )
                                )   
                        )
                )
        )
)

As you can see, relations contains the sorted list of publications, but still retaining the original keys. attributes contains the sorted and renumbered list. When I call $author->toArray(), it is apparently using the relation rather than the attribute. The trick, therefore, is to force Eloquent to assign my renumbered collection to the relation:

$author->setRelation('publications', $sorted->values());

Upvotes: 1

Related Questions