Files
projectsend/app/Support/ConcatenatedPagination.php
ignacionelson 6e47d76ba6 ProjectSend 2.0.0
Client file sharing, rebuilt from the ground up: a private area per
client, resumable uploads, folders, groups and categories, sharing with
expiry dates and download limits, comments, file versions, an activity
log, a REST API, and sixteen languages.

This repository begins here. ProjectSend 2 was developed privately, and
that development history is not published — the previous generation
remains available, with its own history, at projectsend/legacy.

Free software under the GNU General Public License v2, or (at your
option) any later version.
2026-08-14 01:38:12 -03:00

60 lines
2.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support;
use Illuminate\Contracts\Pagination\LengthAwarePaginator as LengthAwarePaginatorContract;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
/**
* Slices N independently-ordered query-builder "sequences" into one flat,
* fixed-size page window — sequence order is fill priority (earlier
* sequences fill first), no merge-sort needed since sequences never
* interleave within a page. E.g. folders-then-files, or
* groups-then-folders-then-files.
*/
class ConcatenatedPagination
{
/**
* @param array<string, Builder<Model>> $sequences ordered name => query builder; order = fill priority
* @param array<string, mixed> $paginatorOptions passed straight to LengthAwarePaginator (path/query)
* @return array{items: array<string, Collection<int, Model>>, paginator: LengthAwarePaginatorContract<int, Model>}
*/
public static function slice(array $sequences, int $page, int $perPage, array $paginatorOptions = []): array
{
$totals = [];
foreach ($sequences as $key => $query) {
$totals[$key] = $query->count();
}
$totalItems = array_sum($totals);
$remainingOffset = ($page - 1) * $perPage;
$remainingLimit = $perPage;
$items = [];
foreach ($sequences as $key => $query) {
$total = $totals[$key];
if ($remainingLimit <= 0 || $remainingOffset >= $total) {
$items[$key] = collect();
$remainingOffset = max(0, $remainingOffset - $total);
continue;
}
$limit = min($remainingLimit, $total - $remainingOffset);
$items[$key] = $query->skip($remainingOffset)->take($limit)->get();
$remainingLimit -= $limit;
$remainingOffset = 0;
}
$paginator = new LengthAwarePaginator([], $totalItems, $perPage, $page, $paginatorOptions);
return ['items' => $items, 'paginator' => $paginator];
}
}