hjortur17's avatar

Trying to make custom pagination

Hi, I have been trying to create custom pagination for my data because I'm merging three arrays. But, I'm struggling with mapping my merged data to the same structure as Laravel would do if I would use ->paginate(x) on the model.

Is there a way in Laravel to use the predefined Pagination resource or is there a way to make it look similar?

I have almost achieve this but I think the code is too ugly and would like to know if there is a better way.

Here is my custom pagination function:

function customPaginate($items, $perPage = 20, $page = null, $search = null, $options = [])
{
    $page = $page ?: (Paginator::resolveCurrentPage() ?: 1);

    $items = $items instanceof Collection ? $items : collect($items);

    $paginator = new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);

    $paginationData = [
        'data' => $paginator->items(),
        'links' => [
            'first' => $paginator->url(1),
            'last' => $paginator->url($paginator->lastPage()),
            'prev' => $paginator->previousPageUrl(),
            'next' => $paginator->nextPageUrl(),
        ],
        'meta' => [
            'current_page' => $paginator->currentPage(),
            'from' => $paginator->firstItem(),
            'last_page' => $paginator->lastPage(),
            'links' => collect($paginator->getUrlRange(1, $paginator->lastPage()))->values()->map(function ($url, $page) use ($paginator, $search) {
                $url = 'http://localhost:8000' . $url . ($search ? '&search=' . urlencode($search) : '');

                return [
                    'url' => $page == $paginator->currentPage() ? null : $url,
                    'label' => $page,
                    'active' => $page == $paginator->currentPage(),
                ];
            })->toArray(),
            'path' => $paginator->url(1),
            'per_page' => $paginator->perPage(),
            'to' => $paginator->lastItem(),
            'total' => $paginator->total(),
        ],
    ];

    return $paginationData;
}

And here is how I have been using it:

public function index(Request $request)
    {
        $request->request->add(['domains' => \App\Domain::whereNull("deleted_at")->count()]);
        $request->request->add(['populate' => "type"]);

        $vendors = VendorResource::collection(Vendor::select('name', 'settings')->where('name', 'like', '%' . $request->search . '%')->get(), $request)->collection->toArray();
        $services = ServiceResource::collection(Service::select('name', 'settings')->where('name', 'like', '%' . $request->search . '%')->get(), $request)->collection->toArray();
        $cookies = CookieResource::collection(Cookie::select('name', 'display_name', 'type', 'category_id')->where('name', 'like', '%' . $request->search . '%')->get(), $request)->collection->toArray();

        $results = array_merge($vendors, $services, $cookies);

        $paginatedResults = customPaginate($results, 18, $request->page, $request->search);

        return $paginatedResults;
    }
}
0 likes
2 replies
martinbean's avatar

@hjortur17 How on earth are you intending to paginate three entirely different data sets? What happens if someone requests page 2?

Paginate your data properly. You‘re trying to fix a problem of your own making.

1 like
vincent15000's avatar

Rather than merging the arrays, you should create a database view with the merged datas and retrieve the datas from the view.

Please or to participate in this conversation.