From ae687fd483a238a3517c8a5fb8b461ce8ed05f45 Mon Sep 17 00:00:00 2001 From: Tobias Gross-Vogt <tgros@tugraz.at> Date: Tue, 15 Nov 2022 10:46:14 +0100 Subject: [PATCH] using data provider from core; new pagination handling -> new provider interface --> BREAKING CHANGE --- composer.lock | 8 +- src/API/OrganizationProviderInterface.php | 17 ++-- .../OrganizationCollectionDataProvider.php | 93 ------------------- src/DataProvider/OrganizationDataProvider.php | 90 ++++++++++++++++++ .../OrganizationItemDataProvider.php | 52 ----------- src/Resources/config/services.yaml | 3 +- src/Service/DummyOrganizationProvider.php | 6 +- 7 files changed, 106 insertions(+), 163 deletions(-) delete mode 100644 src/DataProvider/OrganizationCollectionDataProvider.php create mode 100644 src/DataProvider/OrganizationDataProvider.php delete mode 100644 src/DataProvider/OrganizationItemDataProvider.php diff --git a/composer.lock b/composer.lock index 372096b..07269ba 100644 --- a/composer.lock +++ b/composer.lock @@ -169,11 +169,11 @@ }, { "name": "dbp/relay-core-bundle", - "version": "v0.1.55", + "version": "v0.1.56", "source": { "type": "git", "url": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-core-bundle", - "reference": "b1d1eaa5e9efc58a09e6176215c243041df168f3" + "reference": "0183be15e0c582d935420fb558ea293ab6af1b8b" }, "require": { "api-platform/core": "^2.6.8 <2.7.0", @@ -237,7 +237,7 @@ "AGPL-3.0-or-later" ], "description": "The core bundle of the Relay API gateway", - "time": "2022-11-10T10:15:38+00:00" + "time": "2022-11-15T08:43:56+00:00" }, { "name": "doctrine/annotations", @@ -10043,5 +10043,5 @@ "platform-overrides": { "php": "7.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } diff --git a/src/API/OrganizationProviderInterface.php b/src/API/OrganizationProviderInterface.php index 7f02650..52013cc 100644 --- a/src/API/OrganizationProviderInterface.php +++ b/src/API/OrganizationProviderInterface.php @@ -6,13 +6,12 @@ namespace Dbp\Relay\BaseOrganizationBundle\API; use Dbp\Relay\BaseOrganizationBundle\Entity\Organization; use Dbp\Relay\CoreBundle\Exception\ApiError; -use Dbp\Relay\CoreBundle\Pagination\Paginator; interface OrganizationProviderInterface { /** * @param array $options Available options: - * * 'lang' ('de' or 'en') + * * Locale::LANGUAGE_OPTION (language in ISO 639‑1 format) * * LocalData::INCLUDE_PARAMETER_NAME * * @throws ApiError @@ -21,13 +20,15 @@ interface OrganizationProviderInterface /** * @param array $options Available options: - * * string 'lang' ('de' or 'en') - * * array 'identifiers' The list of organizations to return - * * string Organization::SEARCH_PARAMETER_NAME (partial, case-insensitive text search on 'name' attribute) - * * string LocalData::INCLUDE_PARAMETER_NAME - * * string LocalData::QUERY_PARAMETER_NAME + * * Locale::LANGUAGE_OPTION (language in ISO 639‑1 format) + * * 'identifiers' The list of organizations to return + * * Organization::SEARCH_PARAMETER_NAME (partial, case-insensitive text search on 'name' attribute) + * * LocalData::INCLUDE_PARAMETER_NAME + * * LocalData::QUERY_PARAMETER_NAME + * + * @return Organization[] * * @throws ApiError */ - public function getOrganizations(array $options = []): Paginator; + public function getOrganizations(int $currentPageNumber, int $maxNumItemsPerPage, array $options = []): array; } diff --git a/src/DataProvider/OrganizationCollectionDataProvider.php b/src/DataProvider/OrganizationCollectionDataProvider.php deleted file mode 100644 index 2a85afc..0000000 --- a/src/DataProvider/OrganizationCollectionDataProvider.php +++ /dev/null @@ -1,93 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Dbp\Relay\BaseOrganizationBundle\DataProvider; - -use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface; -use ApiPlatform\Core\DataProvider\PaginatorInterface; -use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; -use Dbp\Relay\BaseOrganizationBundle\API\OrganizationProviderInterface; -use Dbp\Relay\BaseOrganizationBundle\API\OrganizationsByPersonProviderInterface; -use Dbp\Relay\BaseOrganizationBundle\Entity\Organization; -use Dbp\Relay\CoreBundle\Exception\ApiError; -use Dbp\Relay\CoreBundle\Helpers\Locale; -use Dbp\Relay\CoreBundle\LocalData\LocalData; -use Dbp\Relay\CoreBundle\Pagination\Pagination; -use Dbp\Relay\CoreBundle\Pagination\Paginator; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Response; - -final class OrganizationCollectionDataProvider extends AbstractController implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface -{ - public const MAX_ITEMS_PER_PAGE = 250; - - /** @var OrganizationProviderInterface */ - private $organizationProvider; - - /** @var OrganizationsByPersonProviderInterface */ - private $organizationsByPersonProvider; - - /** @var Locale */ - private $locale; - - public function __construct(OrganizationProviderInterface $organizationProvider, Locale $locale, OrganizationsByPersonProviderInterface $organizationsByPersonProvider) - { - $this->organizationProvider = $organizationProvider; - $this->locale = $locale; - $this->organizationsByPersonProvider = $organizationsByPersonProvider; - } - - public function supports(string $resourceClass, string $operationName = null, array $context = []): bool - { - return Organization::class === $resourceClass; - } - - public function getCollection(string $resourceClass, string $operationName = null, array $context = []): Paginator - { - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); - - $filters = $context['filters'] ?? []; - $options = []; - - if ($search = ($filters['search'] ?? null)) { - $options['search'] = $search; - } - - LocalData::addOptions($options, $filters); - - $filters['partialPagination'] = true; - Pagination::addOptions($options, $filters, self::MAX_ITEMS_PER_PAGE); - - // @deprecate 'lang' filter is deprecate, use 'Accept-Language' header instead - if (($lang = $filters['lang'] ?? null) !== null) { - $options[Locale::LANGUAGE_OPTION] = $lang; - } else { - $this->locale->addLanguageOption($options); - } - - //------------------------------------------------------------------------- - // @deprecate The 'person' filter is deprecate. Use the 'identifiers' filter in your custom organizations wrapper. - $personId = $filters['person'] ?? ''; - if ($personId !== '') { - if ($personId !== $this->getUser()->getUserIdentifier()) { - throw new ApiError(Response::HTTP_UNAUTHORIZED, 'only allowed with ID of currently logged-in person'); - } - - $organizations = []; - $orgIdPaginator = $this->organizationsByPersonProvider->getOrganizationsByPerson($personId, $options); - foreach ($orgIdPaginator as $organizationId) { - $organizations[] = $this->organizationProvider->getOrganizationById($organizationId, $options); - } - - if ($orgIdPaginator instanceof PaginatorInterface) { - return Pagination::createFullPaginator($organizations, $options, intval($orgIdPaginator->getTotalItems())); - } else { - return Pagination::createPartialPaginator($organizations, $options); - } - } - //------------------------------------------------------------------------- - - return $this->organizationProvider->getOrganizations($options); - } -} diff --git a/src/DataProvider/OrganizationDataProvider.php b/src/DataProvider/OrganizationDataProvider.php new file mode 100644 index 0000000..a2bc68d --- /dev/null +++ b/src/DataProvider/OrganizationDataProvider.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +namespace Dbp\Relay\BaseOrganizationBundle\DataProvider; + +use Dbp\Relay\BaseOrganizationBundle\API\OrganizationProviderInterface; +use Dbp\Relay\BaseOrganizationBundle\API\OrganizationsByPersonProviderInterface; +use Dbp\Relay\BaseOrganizationBundle\Entity\Organization; +use Dbp\Relay\CoreBundle\DataProvider\AbstractDataProvider; +use Dbp\Relay\CoreBundle\Exception\ApiError; +use Dbp\Relay\CoreBundle\Locale\Locale; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Response; + +class OrganizationDataProvider extends AbstractDataProvider +{ + /** @var OrganizationProviderInterface */ + private $organizationProvider; + + /** @var OrganizationsByPersonProviderInterface */ + private $organizationsByPersonProvider; + + /** @var RequestStack */ + private $requestStack; + + public function __construct(OrganizationProviderInterface $organizationProvider, OrganizationsByPersonProviderInterface $organizationsByPersonProvider, RequestStack $requestStack) + { + $this->organizationProvider = $organizationProvider; + $this->organizationsByPersonProvider = $organizationsByPersonProvider; + $this->requestStack = $requestStack; + } + + protected function getResourceClass(): string + { + return Organization::class; + } + + protected function getItemById($id, array $options = []): object + { + //------------------------------------------------------------------------- + // @deprecate 'lang' query parameter is deprecate, use 'Accept-Language' header instead + $queryParameters = $this->requestStack->getCurrentRequest()->query->all(); + $this->tryAddDeprecatedLangQueryParameter($options, $queryParameters); + //------------------------------------------------------------------------- + + return $this->organizationProvider->getOrganizationById($id, $options); + } + + protected function getPage(int $currentPageNumber, int $maxNumItemsPerPage, array $filters = [], array $options = []): array + { + //------------------------------------------------------------------------- + // @deprecate 'lang' query parameter is deprecate, use 'Accept-Language' header instead + $this->tryAddDeprecatedLangQueryParameter($options, $filters); + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // @deprecate The 'person' filter is deprecate. Use the 'identifiers' filter in your custom organization wrapper. + $personId = $filters['person'] ?? ''; + if ($personId !== '') { + if ($personId !== $this->getUser()->getUserIdentifier()) { + throw new ApiError(Response::HTTP_UNAUTHORIZED, 'only allowed with ID of currently logged-in person'); + } + + $organizations = []; + foreach ($this->organizationsByPersonProvider->getOrganizationsByPerson($personId, $options) as $organizationId) { + $organizations[] = $this->organizationProvider->getOrganizationById($organizationId, $options); + } + + return $organizations; + } + //------------------------------------------------------------------------- + + if ($search = ($filters['search'] ?? null)) { + $options['search'] = $search; + } + + return $this->organizationProvider->getOrganizations($currentPageNumber, $maxNumItemsPerPage, $options); + } + + /** + * @deprecate 'lang' query parameter is deprecated, use 'Accept-Language' header instead + */ + private function tryAddDeprecatedLangQueryParameter(array &$targetOptions, array $filters) + { + if (($lang = $filters['lang'] ?? null) !== null) { + $targetOptions[Locale::LANGUAGE_OPTION] = $lang; + } + } +} diff --git a/src/DataProvider/OrganizationItemDataProvider.php b/src/DataProvider/OrganizationItemDataProvider.php deleted file mode 100644 index 515a5da..0000000 --- a/src/DataProvider/OrganizationItemDataProvider.php +++ /dev/null @@ -1,52 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Dbp\Relay\BaseOrganizationBundle\DataProvider; - -use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; -use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; -use Dbp\Relay\BaseOrganizationBundle\API\OrganizationProviderInterface; -use Dbp\Relay\BaseOrganizationBundle\Entity\Organization; -use Dbp\Relay\CoreBundle\Helpers\Locale; -use Dbp\Relay\CoreBundle\LocalData\LocalData; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; - -final class OrganizationItemDataProvider extends AbstractController implements ItemDataProviderInterface, RestrictedDataProviderInterface -{ - /** @var OrganizationProviderInterface */ - private $api; - - /** @var Locale */ - private $locale; - - public function __construct(OrganizationProviderInterface $api, Locale $locale) - { - $this->api = $api; - $this->locale = $locale; - } - - public function supports(string $resourceClass, string $operationName = null, array $context = []): bool - { - return Organization::class === $resourceClass; - } - - public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): ?Organization - { - $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); - - $filters = $context['filters'] ?? []; - $options = []; - - LocalData::addOptions($options, $filters); - - // @deprecate 'lang' filter is deprecate, use 'Accept-Language' header instead - if (($lang = $filters['lang'] ?? null) !== null) { - $options[Locale::LANGUAGE_OPTION] = $lang; - } else { - $this->locale->addLanguageOption($options); - } - - return $this->api->getOrganizationById($id, $options); - } -} diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index b799db5..0e66309 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -1,6 +1,5 @@ services: - Dbp\Relay\BaseOrganizationBundle\DataProvider\: - resource: '../../DataProvider' + Dbp\Relay\BaseOrganizationBundle\DataProvider\OrganizationDataProvider: autowire: true autoconfigure: true diff --git a/src/Service/DummyOrganizationProvider.php b/src/Service/DummyOrganizationProvider.php index 9a85591..bbb7e6c 100644 --- a/src/Service/DummyOrganizationProvider.php +++ b/src/Service/DummyOrganizationProvider.php @@ -6,8 +6,6 @@ namespace Dbp\Relay\BaseOrganizationBundle\Service; use Dbp\Relay\BaseOrganizationBundle\API\OrganizationProviderInterface; use Dbp\Relay\BaseOrganizationBundle\Entity\Organization; -use Dbp\Relay\CoreBundle\Pagination\Paginator; -use Dbp\Relay\CoreBundle\Pagination\WholeResultPaginator; class DummyOrganizationProvider implements OrganizationProviderInterface { @@ -20,8 +18,8 @@ class DummyOrganizationProvider implements OrganizationProviderInterface return $org; } - public function getOrganizations(array $options = []): Paginator + public function getOrganizations(int $currentPageNumber, int $maxNumItemsPerPage, array $options = []): array { - return new WholeResultPaginator([$this->getOrganizationById('foo', $options)], 1, 30); + return [$this->getOrganizationById('foo', $options)]; } } -- GitLab