Home > OS >  Why pagination request raise error adding calculating in map?
Why pagination request raise error adding calculating in map?

Time:10-07

In laravel 8 app when in pagination request I use mapping with calculated new field :

$hostelDataRows   = Hostel
    ::orderBy('created_at', 'desc')
        ->where('hostels.id', 41) // debug
    ->with('state')
    ->with('region')
    ->with('user')
    ->withCount('hostelRooms')
    ->withCount('hostelInquiries')
    ->withCount('hostelImages')

    ->getByName($this->filters['name'], true)
    ->getByStatus($this->filters['status'], true)
    ->getByStateId($this->filters['state_id'], true)
    ->getByFeature($this->filters['feature'], true)
    ->addSelect([
        'min_hostel_rooms_price' =>
            HostelRoom::query()
                     ->selectRaw('MIN(price)')
                     ->whereColumn('hostel_id', 'hostels.id'),
    ])

    ->paginate($backend_per_page)
    ->map(function ($hostelItem) {
        if ($hostelItem->hostel_rooms_count > 0 and $hostelItem->hostel_inquiries_count > 0 and $hostelItem->hostel_images_count > 0 ) {
            $hostelItem->info_text = 'Has ' . ($hostelItem->hostel_rooms_count .  pluralize3( $hostelItem->hostel_rooms_count, 'no rooms', 'room', 'rooms' ) );
        }

        return $hostelItem;
    })
;

I got error :

Method Illuminate\Database\Eloquent\Collection::links does not exist. (

it is clear that with mappimg $hostelDataRows is not pagination object anyway...

How that can be fixed ?

Thanks!

CodePudding user response:

When you use map() on a Paginator instance, you will get a Collection instance back (I think it is Illuminate\Database\Eloquent\Collection here). So you can't put map() in front of it since that would require you to fetch the query (which is dependent on the paginator page). However there are some other solutions:

Solution 1: use the tap() helper

The tap() helper always returns the argument to the function. Since Collection map() (and transform() which is very similar) modify the instance Collection itself, this works as intended and you now get your original paginator instance back (with the extra properties from your map-function).

return tap($query->paginate())->map(...);

Solution 2: use a getInfoTextAttribute() accessor

In your specific usecase you might just as well make a property for your $hostelItem if you are going to use this property more often, like so:

// Models/HostelItem.php

/**
 * @property string $info_text
 */
class HostelItem extends Model
{
    public function getInfoTextAttribute()
    {
        return 'Has ' . ($this->hostel_rooms_count .  pluralize3( $this->hostel_rooms_count, 'no rooms', 'room', 'rooms' ) );
    }
}

I've added a @property annotation so you can have code assist in most of your files. Now, simply call $hostelItem->info_text and you're done. no need for a map.

  • Related