mirror of
https://github.com/kevinpapst/kimai2.git
synced 2025-03-14 21:22:46 +00:00
Improve pagination support in API (#5073)
This commit is contained in:
parent
4076e1c3d3
commit
13649e146c
5 changed files with 70 additions and 23 deletions
migrations
src/API
tests
|
@ -43,6 +43,10 @@ WHERE kp.value > 0
|
|||
'value' => 'day',
|
||||
]);
|
||||
}
|
||||
|
||||
if (\count($ids) === 0) {
|
||||
$this->preventEmptyMigrationWarning();
|
||||
}
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
Loading…
Reference in a new issue