0
0
Fork 0
mirror of https://github.com/kevinpapst/kimai2.git synced 2025-03-14 21:22:46 +00:00

Improve pagination support in API ()

This commit is contained in:
Kevin Papst 2024-09-22 17:26:02 +02:00 committed by GitHub
parent 4076e1c3d3
commit 13649e146c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 23 deletions

View file

@ -43,6 +43,10 @@ WHERE kp.value > 0
'value' => 'day',
]);
}
if (\count($ids) === 0) {
$this->preventEmptyMigrationWarning();
}
}
public function down(Schema $schema): void

View file

@ -13,6 +13,7 @@ use App\Entity\User;
use App\Repository\Query\BaseQuery;
use App\Timesheet\DateTimeFactory;
use App\Utils\Pagination;
use FOS\RestBundle\Request\ParamFetcherInterface;
use FOS\RestBundle\View\View;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
@ -52,6 +53,46 @@ abstract class BaseApiController extends AbstractController
return DateTimeFactory::createByUser($user);
}
protected function prepareQuery(BaseQuery $query, ParamFetcherInterface $paramFetcher): void
{
$query->setIsApiCall(true);
$query->setCurrentUser($this->getUser());
// there is no function has() in ParamFetcherInterface, so we need to use all() and check for the key
$all = $paramFetcher->all(true);
if (\array_key_exists('page', $all)) {
$page = $all['page'];
if (is_numeric($page)) {
$query->setPage((int) $page);
}
}
if (\array_key_exists('size', $all)) {
$size = $all['size'];
if (is_numeric($size)) {
$query->setPageSize((int) $size);
}
}
if (\array_key_exists('pageSize', $all)) {
$size = $all['pageSize'];
if (is_numeric($size)) {
$query->setPageSize((int) $size);
}
}
}
protected function createPaginatedView(Pagination $pagination): View
{
$results = (array) $pagination->getCurrentPageResults();
$view = new View($results, 200);
$this->addPagination($view, $pagination);
return $view;
}
protected function addPagination(View $view, Pagination $pagination): void
{
$view->setHeader('X-Page', (string) $pagination->getCurrentPage());

View file

@ -10,7 +10,6 @@
namespace App\API;
use App\Entity\Invoice;
use App\Entity\User;
use App\Repository\CustomerRepository;
use App\Repository\InvoiceRepository;
use App\Repository\Query\InvoiceArchiveQuery;
@ -39,7 +38,7 @@ final class InvoiceController extends BaseApiController
}
/**
* Returns a collection of invoices (which are visible to the user)
* Returns a paginated collection of invoices.
*
* Needs permission: view_invoice
*/
@ -54,11 +53,8 @@ final class InvoiceController extends BaseApiController
#[Rest\QueryParam(name: 'size', requirements: '\d+', strict: true, nullable: true, description: 'The amount of entries for each page (default: 50)')]
public function cgetAction(ParamFetcherInterface $paramFetcher, CustomerRepository $customerRepository): Response
{
/** @var User $user */
$user = $this->getUser();
$query = new InvoiceArchiveQuery();
$query->setCurrentUser($user);
$this->prepareQuery($query, $paramFetcher);
$factory = $this->getDateTimeFactory();
$begin = $paramFetcher->get('begin');
@ -79,29 +75,15 @@ final class InvoiceController extends BaseApiController
}
}
$page = $paramFetcher->get('page');
if (\is_string($page) && $page !== '') {
$query->setPage((int) $page);
}
$size = $paramFetcher->get('size');
if (is_numeric($size)) {
$query->setPageSize((int) $size);
}
/** @var array<int> $customers */
$customers = $paramFetcher->get('customers');
foreach ($customerRepository->findByIds(array_unique($customers)) as $customer) {
$query->addCustomer($customer);
}
$query->setIsApiCall(true);
$data = $this->repository->getPagerfantaForQuery($query);
$results = (array) $data->getCurrentPageResults();
$view = new View($results, 200);
$view = $this->createPaginatedView($data);
$view->getContext()->setGroups(self::GROUPS_COLLECTION);
$this->addPagination($view, $data);
return $this->viewHandler->handle($view);
}

View file

@ -76,6 +76,25 @@ class InvoiceControllerTest extends APIControllerBaseTest
self::assertApiResponseTypeStructure('InvoiceCollection', $result[0]);
}
public function testGetCollectionWithPagination(): void
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->importInvoiceFixtures(20);
$query = ['page' => 2, 'size' => 4];
$this->assertAccessIsGranted($client, '/api/invoices', 'GET', $query);
$content = $client->getResponse()->getContent();
$this->assertIsString($content);
$result = json_decode($content, true);
$this->assertIsArray($result);
$this->assertNotEmpty($result);
$this->assertEquals(4, \count($result));
$this->assertPagination($client->getResponse(), 2, 4, 5, 20);
self::assertApiResponseTypeStructure('InvoiceCollection', $result[0]);
}
public function testGetEntityIsSecure(): void
{
$client = $this->getClientForAuthenticatedUser();

View file

@ -57,11 +57,12 @@ class InvoiceFixtures implements TestFixture
$invoice->setTax($tax);
$invoice->setCustomer($customers[array_rand($customers)]);
$invoice->setInvoiceNumber($i . '_ ' . $faker->text(10));
$prefix = uniqid($i . '_') . '_';
$invoice->setInvoiceNumber($prefix . $faker->randomNumber(3));
$invoice->setFilename($prefix . $faker->randomNumber(3));
$invoice->setCreatedAt($faker->dateTimeBetween('-1 year', 'now'));
$invoice->setUser($users[array_rand($users)]);
$invoice->setDueDays($faker->randomNumber(2));
$invoice->setFilename($faker->text(30));
$invoice->setComment($faker->text(300));
$invoice->setCurrency($faker->currencyCode());