Akeno's avatar

Many-to-many -> Pagination with pivot table data

Hi,

I have a many-to-many relation:

locations
messages
location_messages

Now, I want to paginate all of the messages from a Location:

$location->messages()->paginate(10);

That works but there is one problem: Inside my pivot table, there is some important data I need. The way from above does get this data, but it does not put it within a "->pivot" attribute. Normally I can access pivot data like this:

$messages = $location->load('messages')->messages;
$messages->pivot->pivotData;

But if I work with pagination, the pivot data is put as attribute from Message, not as attribute of pivot:

$messages = $location->messages()->paginate(10);
$messages->items()[0]->pivotData // items()[0] is a Message model

So I don't need the "->pivot->" to access it. That would be fine, but I have several methods that use "->pivot->" to access the data. And they don't work when I use pagination to get the messages.

I could manually copy these to a pivot attribute, but that's not really convenient and can cause trouble I think.

Any ideas? Thank you :)

0 likes
16 replies
JarekTkaczyk's avatar

@Akeno I meant exact version. Anyway, update to v5.0.6+ and you'll be OK. paginate method on BelongsToMany was added then.

JarekTkaczyk's avatar

@Akeno That's strange. Run $location->messages()->paginate(1); in cli artisan tinker and show the output

Akeno's avatar

@JarekTkaczyk Here:

<Illuminate\Pagination\LengthAwarePaginator #000000007aad79a3000000001d5660fd> {}

I don't know what that is :D If diedump the result and look at the browser, I get a Paginator object

JarekTkaczyk's avatar

@Akeno Yeah, that's the paginator class. Did I mention I wanted to see the collection :)

$location->messages()->paginate(1)->getCollection()->toArray().

Akeno's avatar

Wow, that is strange:

[
       [
           "id"                 => 3,
           "subject"            => "test",
           "content"            => "test message",
           "integrity"          => 90,
           "sender_location_id" => 0,
           "system"             => 0,
           "message_type_id"    => 5,
           "created_at"         => "2015-04-08 15:05:16",
           "updated_at"         => "2015-04-08 15:05:16",
           "pivot"              => [
               "location_id"    => 1,
               "message_id"     => 3,
               "seen"           => 0,
               "broken_subject" => "",
               "broken_content" => "",
               "receive_time"   => "0000-00-00 00:00:00"
           ]
       ]
   ]

If I do the exact thing in the browser I get this:

array:1 [▼
  0 => array:15 [▼
    "id" => 3
    "subject" => "test"
    "content" => "test message"
    "integrity" => 90
    "sender_location_id" => 0
    "system" => 0
    "message_type_id" => 5
    "created_at" => "2015-04-08 15:05:16"
    "updated_at" => "2015-04-08 15:05:16"
    "location_id" => 1
    "message_id" => 3
    "seen" => 0
    "broken_subject" => ""
    "broken_content" => ""
    "receive_time" => "0000-00-00 00:00:00"
  ]
]
Akeno's avatar

Oh, I found something: I tried to put "simplePaginate(1)" instead of "paginate(1)" earlier because I thought it could solve the problem.

Actually, it was causing the problem I think. The browser output I posted was the one with "simplePaginate". So the "simple" is causing the problem. Does this make sense?

JarekTkaczyk's avatar

@Akeno well, there's no simplePaginate method on the BelongsToMany, so, yeah, that's the problem.

1 like
Akeno's avatar

Oh, okay. Is this a bug or a feature? :D

But okay, then I'll have to stick with paginate :)

JarekTkaczyk's avatar

@Akeno It is somewhat a bug, inconsistency at least. Are you willing to fix it and send a PR, or should I? :)

1 like
Akeno's avatar

@JarekTkaczyk Well, I am willing to fix it but I don't know if I can describe the problem properly or even fix it :D I don't even know what this "->pivot->" thing is called, if it's an attribute, an array, or an object. If you want to send the PR that would be great :)

ben_s247's avatar

I could be wrong about this but I'm doing something similar to this senario and I'm using something like this in the controller

    $locations = Location::with('messages')->OrderBy('$column_name',    'asc|desc')->paginate($number_of_items_per_page);
    //to check whats being passed through use
    //foreach($locations as $location)
    //{
    //  dd($location->message);
    //}
    return view('location.index', compact('locations');

please note that you need the relationship setup on the model:

    public function message()
    {
        return $this->belongsToMany(Location::class);
    }

i can't recommend the laracasts generators enough they make doing piviot tables trivial since they have lots of rules that aren't obvious like alphabetical order.

Please or to participate in this conversation.