Skip to content

Commit

Permalink
MovieCollectionDataProvider using MovieRepository
Browse files Browse the repository at this point in the history
  • Loading branch information
aratinau committed Jul 3, 2021
1 parent ea7db84 commit c33a794
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 22 deletions.
63 changes: 42 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,20 @@

Inspired from https://github.com/api-platform/demo

This is an example using a custom `CityFilter` filtering on raw data from the file `Repository/City/data/worldcities.csv`
There is tree examples in this repo

CityFilter pass the `sort` and `order` params to the context and this context it's processed in the `CityCollectionDataProvider`

## Install

composer install

php bin/console doctrine:schema:update --env=dev --dump-sql

php bin/console doctrine:schema:update --env=dev --force

php bin/console hautelook:fixtures:load
## First Example use raw data from a csv file

## Launch

symfony serve --no-tls
Example using a custom `CityFilter` filtering on raw data from the file `Repository/City/data/worldcities.csv`

## Usage
CityFilter pass the `sort` and `order` params to the context and this context it's processed in the `CityCollectionDataProvider`

sort and filter on raw data from csv
### Usage

sort and filter on raw data from csv
`/api/cities?search[key]=tokyo&order[key]=desc&page=1`

custom controller action from database using Paginator
`api/movies/custom-action?page=1&order[id]=asc&order[title]=desc`

### Keys available
#### Keys available

- id
- city
Expand All @@ -42,3 +28,38 @@ custom controller action from database using Paginator
- admin_name
- capital
- population


## Second example use custom controller

On path `/movies/custom-action` the action `CustomMovieAction` is called and page and order use `getCustom` method from `MovieRepository`.
The pagination is available

### Usage

custom controller action from database using Paginator
`api/movies/custom-action?page=1&order[id]=asc&order[title]=desc`

## Third example use MovieCollectionDataProvider and repository

On the normalization_context group `normalization-custom-action-using-dataprovider` the MovieCollectionDataProvider is called and the resust is from the repository. The param `isPublished` can be used and the result is sorted by the value (true or false) asked.
The param `order` can be `title` or `id` and ordered by `asc|desc`. The pagination is available

### Usage

data provider using repository (by group from normalization_context on Movie entity)
`api/movies/custom-action-using-dataprovider?page=2&order[title]=desc&isPublished=false`

## Install

composer install

php bin/console doctrine:schema:update --env=dev --dump-sql

php bin/console doctrine:schema:update --env=dev --force

php bin/console hautelook:fixtures:load

## Launch

symfony serve --no-tls
1 change: 1 addition & 0 deletions fixtures/movie.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
App\Entity\Movie:
movie_{1..1000}:
title: <text(10, 700)>
isPublished: '<numberBetween(0, 1)>'
27 changes: 27 additions & 0 deletions src/DataProvider/Extension/MovieCollectionExtensionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\DataProvider\Extension;

use App\Entity\City;

interface MovieCollectionExtensionInterface
{
/**
* Returns the final result object.
*
* @param array<int, City> $collection
* @param array<string, mixed> $context
*
* @return iterable<City>
*/
public function getResult(array $collection, string $resourceClass, string $operationName = null, array $context = []): iterable;

/**
* Tells if the extension is enabled or not.
*
* @param array<string, mixed> $context
*/
public function isEnabled(string $resourceClass = null, string $operationName = null, array $context = []): bool;
}
35 changes: 35 additions & 0 deletions src/DataProvider/Extension/MoviePaginationExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace App\DataProvider\Extension;

use ApiPlatform\Core\DataProvider\ArrayPaginator;
use ApiPlatform\Core\DataProvider\Pagination;

final class MoviePaginationExtension implements MovieCollectionExtensionInterface
{
private $pagination;
public function __construct(Pagination $pagination)
{
$this->pagination = $pagination;
}

/**
* {@inheritdoc}
*/
public function getResult(array $collection, string $resourceClass, string $operationName = null, array $context = []): iterable
{
[, $offset, $itemPerPage] = $this->pagination->getPagination($resourceClass, $operationName, $context);

return new ArrayPaginator($collection, $offset, $itemPerPage);
}

/**
* {@inheritdoc}
*/
public function isEnabled(string $resourceClass = null, string $operationName = null, array $context = []): bool
{
return $this->pagination->isEnabled($resourceClass, $operationName, $context);
}
}
61 changes: 61 additions & 0 deletions src/DataProvider/MovieCollectionDataProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace App\DataProvider;

use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\DataProvider\Extension\MovieCollectionExtensionInterface;
use App\Entity\Movie;
use App\Repository\MovieRepository;

final class MovieCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
{
private $paginationExtension;
private $movieRepository;

public function __construct(
MovieCollectionExtensionInterface $paginationExtension,
MovieRepository $movieRepository
) {
$this->paginationExtension = $paginationExtension;
$this->movieRepository = $movieRepository;
}

/**
* @param array<string, mixed> $context
*/
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
{
if (empty($context["groups"])) {
return false;
}

return
Movie::class === $resourceClass &&
$context["groups"] === "normalization-custom-action-using-dataprovider"
;
}

/**
* @param array<string, mixed> $context
*
* @throws \RuntimeException
*
* @return iterable<Movie>
*/
public function getCollection(string $resourceClass, string $operationName = null, array $context = []): iterable
{
$isPublished = [];
if (isset($context['filters']['isPublished'])) {
$isPublished['isPublished'] = $context['filters']['isPublished'];
}

$movies = $this->movieRepository->findBy($isPublished,
$context['filters']['order']
);

return $this->paginationExtension->getResult($movies, $resourceClass, $operationName, $context);
}
}
28 changes: 27 additions & 1 deletion src/Entity/Movie.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use App\Repository\MovieRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Controller\CustomMovieAction;
use ApiPlatform\Core\Annotation\ApiFilter;
use Symfony\Component\Serializer\Annotation\Groups;

/**
* @ApiResource(
Expand All @@ -16,6 +16,12 @@
* "deserialize"=false,
* "path"="/movies/custom-action",
* "controller"=CustomMovieAction::class
* },
* "custom-action-using-dataprovider"={
* "method"="GET",
* "deserialize"=false,
* "path"="/movies/custom-action-using-dataprovider",
* "normalization_context"={"groups" = "normalization-custom-action-using-dataprovider"}
* }
* }
* )
Expand All @@ -27,14 +33,22 @@ class Movie
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({"normalization-custom-action-using-dataprovider"})
*/
private $id;

/**
* @ORM\Column(type="string", length=255)
* @Groups({"normalization-custom-action-using-dataprovider"})
*/
private $title;

/**
* @ORM\Column(type="boolean")
* @Groups({"normalization-custom-action-using-dataprovider"})
*/
private $isPublished;

public function getId(): ?int
{
return $this->id;
Expand All @@ -51,4 +65,16 @@ public function setTitle(string $title): self

return $this;
}

public function getIsPublished(): ?bool
{
return $this->isPublished;
}

public function setIsPublished(bool $isPublished): self
{
$this->isPublished = $isPublished;

return $this;
}
}

0 comments on commit c33a794

Please sign in to comment.