Skip to content

Commit 26c88ed

Browse files
martinharderdunglas
authored andcommitted
Examples for custom controllers (#638)
* Examples for custom controllers Many are missing examples how to use pagination with custom controllers. This could help. * Update pagination.md * Update core/pagination.md Co-Authored-By: martinharder <[email protected]> * Update core/pagination.md Co-Authored-By: martinharder <[email protected]> * Use method in registry instead of service The method is moved to the registry. Controller extends AbstractController.
1 parent 76eb1e8 commit 26c88ed

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

core/pagination.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,3 +345,128 @@ class Book
345345
```
346346

347347
Please note that this parameter will always be forced to false when the resource have composite keys due to a [bug in doctrine](https://github.com/doctrine/doctrine2/issues/2910)
348+
349+
## Custom Controller Action
350+
351+
In case you're using a custom controller action make sure you return the `Paginator` object to get the full hydra response with `hydra:view` (which contains information about first, last, next and previous page). The following examples show how to handle it within a repository method. The controller needs to pass through the page number. You will need to use the Doctrine Paginator and pass it to the API Platform Paginator.
352+
353+
First example:
354+
355+
```php
356+
<?php
357+
358+
//src/Repository/BookRepository.php
359+
360+
namespace App\Repository;
361+
362+
use App\Entity\Book;
363+
use App\Entity\User;
364+
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
365+
use Doctrine\ORM\EntityManagerInterface;
366+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
367+
use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;
368+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator;
369+
use Doctrine\Common\Collections\Criteria;
370+
371+
class BookRepository extends ServiceEntityRepository
372+
{
373+
const ITEMS_PER_PAGE = 20;
374+
375+
private $tokenStorage;
376+
377+
public function __construct(
378+
RegistryInterface $registry,
379+
TokenStorageInterface $tokenStorage
380+
) {
381+
$this->tokenStorage = $tokenStorage;
382+
parent::__construct($registry, Book::class);
383+
}
384+
385+
public function getBooksByFavoriteAuthor(int $page = 1): Paginator
386+
{
387+
$firstResult = ($page -1) * self::ITEMS_PER_PAGE;
388+
389+
$user = $this->tokenStorage->getToken()->getUser();
390+
$queryBuilder = $this->createQueryBuilder();
391+
$queryBuilder->select('b')
392+
->from(Book::class, 'b')
393+
->where('b.author = :author')
394+
->setParameter('author', $user->getFavoriteAuthor()->getId())
395+
->andWhere('b.publicatedOn IS NOT NULL');
396+
397+
$criteria = Criteria::create()
398+
->setFirstResult($firstResult)
399+
->setMaxResults(self::ITEMS_PER_PAGE);
400+
$queryBuilder->addCriteria($criteria);
401+
402+
$doctrinePaginator = new DoctrinePaginator($queryBuilder);
403+
$paginator = new Paginator($doctrinePaginator);
404+
405+
return $paginator;
406+
}
407+
}
408+
```
409+
The Controller would look like this:
410+
411+
```php
412+
<?php
413+
414+
// src/Controller/Book/GetBooksByFavoriteAuthorAction.php
415+
416+
namespace App\Controller\Book;
417+
418+
use ApiPlatform\Core\Bridge\Doctrine\Orm\Paginator;
419+
use App\Service\Book\BookService;
420+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
421+
use Symfony\Component\HttpFoundation\Request;
422+
423+
class GetBooksByFavoriteAuthorAction extends AbstractController
424+
{
425+
public function __invoke(Request $request, BookService $bookService): Paginator
426+
{
427+
$page = (int) $request->query->get('page', 1);
428+
429+
return $bookService->getBooksByFavoriteAuthor($page);
430+
}
431+
}
432+
```
433+
434+
The service need to use the proper repository method.
435+
You can also use the Query object inside the repository method and pass it to the Paginator instead of passing the QueryBuilder and using Criteria. Second Example:
436+
437+
```php
438+
<?php
439+
440+
//src/Repository/BookRepository.php
441+
442+
namespace App\Repository;
443+
444+
// use...
445+
446+
class BookRepository extends ServiceEntityRepository
447+
{
448+
// constant, variables and constructor...
449+
450+
public function getBooksByFavoriteAuthor(int $page = 1): Paginator
451+
{
452+
$firstResult = ($page -1) * self::ITEMS_PER_PAGE;
453+
454+
$user = $this->tokenStorage->getToken()->getUser();
455+
$queryBuilder = $this->createQueryBuilder();
456+
$queryBuilder->select('b')
457+
->from(Book::class, 'b')
458+
->where('b.author = :author')
459+
->setParameter('author', $user->getFavoriteAuthor()->getId())
460+
->andWhere('b.publicatedOn IS NOT NULL');
461+
462+
$query = $queryBuilder->getQuery()
463+
->setFirstResult($firstResult)
464+
->setMaxResults(self::ITEMS_PER_PAGE);
465+
466+
$doctrinePaginator = new DoctrinePaginator($query);
467+
$paginator = new Paginator($doctrinePaginator);
468+
469+
return $paginator;
470+
}
471+
}
472+
```

0 commit comments

Comments
 (0)