Пагинат для коллекции, Laravel - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь добавить несколько новых значений для каждого пользователя из foreach, но поскольку я использую get, теперь я не могу использовать paginate для ответа, но мне также нужно добавить эти значения каждому пользователю. Есть идеи?

public function statistics()
    {
        $users = User::select(['id', 'name'])->get();
        foreach ($users as $key => $user) {
            $history = AnswerHistory::where('user_id', '=', $user->id)->get();
            $user->total_votes = count($history);
            $user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
        }

        return response()->json($users);
    }

Ответы [ 3 ]

1 голос
/ 10 апреля 2020

Вы можете создать нумерацию страниц самостоятельно, посмотрите на этот Laravel do c https://laravel.com/docs/7.x/pagination#manually -cagating-a-paginator . Я предлагаю использовать LengthAwarePaginator Вот пример кода с массивом

    // creating pagination
    $offset = max(0, ($page - 1) * $perPage);
    $resultArray = array_slice($result, $offset, $perPage);
    $paginator = new LengthAwarePaginator($resultArray, count($result), $perPage, $page);
    $paginator->setPath(url()->current());
    $paginator->appends(['per_page' => $perPage]);

    return response()->json([
        'message' => 'Success',
        'data'    => $paginator
    ]);

Но я думаю, что в вашем случае есть лучшее "хорошее" решение, вы можете загрузить AnswerHistory с отношением hasMany Laravel и with функция.

1 голос
/ 10 апреля 2020

то, что вы хотите, невозможно в laravel по умолчанию, однако есть несколько вещей, которые вы можете сделать.

Решение первое вы можете вернуть paginator сначала, а затем измените коллекцию.

    $users = User::select(['id', 'name'])->paginate(4)->toArray();

    $users['data'] = array_map(function ($user) {
            $history = AnswerHistory::where('user_id', '=', $user->id)->get();
            $user->total_votes = count($history);
            $user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
        return $user;
    }, $users['data']);

    return  $users;

Решение два Макро способ. Если вы предпочитаете, добавьте макрос Collection в поставщика услуг. Таким образом, вы можете вызвать paginate () для любой коллекции: см. AppServiceProvider. php для примера реализации.

    public function boot()
    {
        Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
            $page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

            return new LengthAwarePaginator(
                $this->forPage($page, $perPage),
                $total ?: $this->count(),
                $perPage,
                $page,
                [
                    'path' => LengthAwarePaginator::resolveCurrentPath(),
                    'pageName' => $pageName,
                ]
            );
        });
    }

, и тогда ваш код будет выглядеть так

        $users = User::select(['id', 'name'])->get();
        foreach ($users as $key => $user) {
            $history = AnswerHistory::where('user_id', '=', $user->id)->get();
            $user->total_votes = count($history);
            $user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
        }

        return response()->json($users->paginate(4));

Решение три Подкласс способ. Там, где вам нужна «страница с возможностью просмотра», отличная от стандартной Illuminate\Support\Collection, внедрите копию Collection.php в свое приложение и просто замените свои операторы use Illuminate\Support\Collection в верхней части зависимых файлов на use App\Support\Collection:

<?php

namespace App\Support;

use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection as BaseCollection;

class Collection extends BaseCollection
{
    public function paginate($perPage, $total = null, $page = null, $pageName = 'page')
    {
        $page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);

        return new LengthAwarePaginator(
            $this->forPage($page, $perPage),
            $total ?: $this->count(),
            $perPage,
            $page,
            [
                'path' => LengthAwarePaginator::resolveCurrentPath(),
                'pageName' => $pageName,
            ]
        );
    }
}

и ваш код будет таким

// use Illuminate\Support\Collection
use App\Support\Collection;

        $users = User::select(['id', 'name'])->get();
        foreach ($users as $key => $user) {
            $history = AnswerHistory::where('user_id', '=', $user->id)->get();
            $user->total_votes = count($history);
            $user->total_time = gmdate("H:i:s", ($history->sum('answer_time')));
        }

        return response()->json((new Collection($users))->paginate(4);
1 голос
/ 10 апреля 2020

Согласно вашему сообщению, User имеет много AnswerHistory. Вы можете строить отношения между ними.

Таким образом, получая total_votes и total_time по withCount:

$users = User::withCount('answerHistories AS total_votes')
     ->withCount(['answerHistories AS total_time' => function($query) {
           $query->select(DB::raw("SUM(answer_time)"));
     }])->paginate(10);

И вы можете получить данные о нумерации страниц по getCollection, и изменить данные внутри:

$users->getCollection()->transform(function ($data) {
    $data->total_time = gmdate('H:i:s', $data->total_time);
    return $data;
});
...