diff --git a/composer.lock b/composer.lock index 372096bf0e48503f683f37648a31be634743bbc3..07269bade0b61b7237bba5b6fd4e827fd3441f8c 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 7f02650425fa10f28a21d6b8185e06d1a1da523e..52013cca9ebc3c26311b8d757ba26a4f8c6aca03 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 2a85afccf8b3f68981c33ed8b66c7dcb5129db40..0000000000000000000000000000000000000000 --- 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 0000000000000000000000000000000000000000..a2bc68d5d0667a695ce7d55cb5db5a907cb70a18 --- /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 515a5da3c0788badf2019b95c94d169d9e4ecc39..0000000000000000000000000000000000000000 --- 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 b799db5b9c717781440148ea2e6825d9646676de..0e663097bdaffe499a5c0af88653ab742900a3f3 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 9a85591ad66d9accecafd8fcb184e66b999a5ba2..bbb7e6c872ecb6513a38bc4e3add85680ef50d09 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)]; } }