From b71eb8cf35683a600bb846329f94a7f24e35f8a2 Mon Sep 17 00:00:00 2001 From: Tobias Gross-Vogt <tgros@tugraz.at> Date: Wed, 23 Mar 2022 09:00:02 +0100 Subject: [PATCH] optionally include local data --- composer.json | 8 +++- composer.lock | 38 ++++++++--------- src/DataProvider/CourseItemDataProvider.php | 13 +++++- src/Entity/Course.php | 3 +- src/Entity/CourseTrait.php | 16 +++++-- src/Resources/config/services.yaml | 5 +++ .../Normalizer/CourseNormalizer.php | 42 +++++++++++++++++++ 7 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 src/Serializer/Normalizer/CourseNormalizer.php diff --git a/composer.json b/composer.json index eef9e41..d25f933 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,13 @@ "api-platform/core": "^2.6", "dbp/relay-base-person-bundle": "^0.1.3", "dbp/relay-core-bundle": "^0.1.11", - "symfony/framework-bundle": "^5.4" + "symfony/config": "^5.4", + "symfony/framework-bundle": "^5.4", + "symfony/security-bundle": "^5.4", + "symfony/security-core": "^5.4", + "symfony/security-guard": "^5.4", + "symfony/validator": "^5.4", + "symfony/yaml": "^5.4" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", diff --git a/composer.lock b/composer.lock index a88955f..8ce0029 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0df1de6656e47e39e70adb1f054ff0ab", + "content-hash": "b9c94ef304f615c39444318e0d0175e8", "packages": [ { "name": "api-platform/core", @@ -4533,16 +4533,16 @@ }, { "name": "symfony/security-bundle", - "version": "v5.4.3", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "d3239128269ae67d78df535f65f41cf02cabdc6c" + "reference": "d6ae2f605fa8e4e0860c1a6574271af2bb4ba16c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/d3239128269ae67d78df535f65f41cf02cabdc6c", - "reference": "d3239128269ae67d78df535f65f41cf02cabdc6c", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/d6ae2f605fa8e4e0860c1a6574271af2bb4ba16c", + "reference": "d6ae2f605fa8e4e0860c1a6574271af2bb4ba16c", "shasum": "" }, "require": { @@ -4615,7 +4615,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v5.4.3" + "source": "https://github.com/symfony/security-bundle/tree/v5.4.5" }, "funding": [ { @@ -4631,20 +4631,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-02-18T16:06:09+00:00" }, { "name": "symfony/security-core", - "version": "v5.4.3", + "version": "v5.4.5", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "b26a44457a4d1a60c79f1c23273e812c4077ce85" + "reference": "11d815ccbff929899a4ec545f9f85185071abd12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/b26a44457a4d1a60c79f1c23273e812c4077ce85", - "reference": "b26a44457a4d1a60c79f1c23273e812c4077ce85", + "url": "https://api.github.com/repos/symfony/security-core/zipball/11d815ccbff929899a4ec545f9f85185071abd12", + "reference": "11d815ccbff929899a4ec545f9f85185071abd12", "shasum": "" }, "require": { @@ -4708,7 +4708,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v5.4.3" + "source": "https://github.com/symfony/security-core/tree/v5.4.5" }, "funding": [ { @@ -4724,7 +4724,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-02-18T16:06:09+00:00" }, { "name": "symfony/security-csrf", @@ -5586,16 +5586,16 @@ }, { "name": "symfony/validator", - "version": "v5.4.3", + "version": "v5.4.6", "source": { "type": "git", "url": "https://github.com/symfony/validator.git", - "reference": "b420894e98f414b9ad5d4494650bf281f6dd6028" + "reference": "ab461eab209e3be062ba9c609d37b37e8364dbe4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/b420894e98f414b9ad5d4494650bf281f6dd6028", - "reference": "b420894e98f414b9ad5d4494650bf281f6dd6028", + "url": "https://api.github.com/repos/symfony/validator/zipball/ab461eab209e3be062ba9c609d37b37e8364dbe4", + "reference": "ab461eab209e3be062ba9c609d37b37e8364dbe4", "shasum": "" }, "require": { @@ -5679,7 +5679,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v5.4.3" + "source": "https://github.com/symfony/validator/tree/v5.4.6" }, "funding": [ { @@ -5695,7 +5695,7 @@ "type": "tidelift" } ], - "time": "2022-01-26T16:28:35+00:00" + "time": "2022-03-02T12:42:23+00:00" }, { "name": "symfony/var-dumper", diff --git a/src/DataProvider/CourseItemDataProvider.php b/src/DataProvider/CourseItemDataProvider.php index 4b5252b..7d51ffa 100644 --- a/src/DataProvider/CourseItemDataProvider.php +++ b/src/DataProvider/CourseItemDataProvider.php @@ -8,7 +8,9 @@ use ApiPlatform\Core\DataProvider\ItemDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use Dbp\Relay\BaseCourseBundle\API\CourseProviderInterface; use Dbp\Relay\BaseCourseBundle\Entity\Course; +use Dbp\Relay\CoreBundle\Exception\ApiError; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; final class CourseItemDataProvider extends AbstractController implements ItemDataProviderInterface, RestrictedDataProviderInterface { @@ -28,8 +30,17 @@ final class CourseItemDataProvider extends AbstractController implements ItemDat { $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); + $options = []; $filters = $context['filters'] ?? []; - $options = ['lang' => $filters['lang'] ?? 'de']; + $options['lang'] = $filters['lang'] ?? 'de'; + + if ($include = ($filters['include'] ?? null)) { + if ($include === 'localData') { + $options['includeLocalData'] = true; + } else { + throw new ApiError(Response::HTTP_BAD_REQUEST, 'requested inclusion of unknown resource '.$include); + } + } return $this->api->getCourseById($id, $options); } diff --git a/src/Entity/Course.php b/src/Entity/Course.php index 88f9169..9e51ace 100644 --- a/src/Entity/Course.php +++ b/src/Entity/Course.php @@ -60,7 +60,8 @@ use Symfony\Component\Serializer\Annotation\Groups; * "tags" = {"BaseCourse"}, * "parameters" = { * {"name" = "identifier", "in" = "path", "description" = "Id of course", "required" = true, "type" = "string", "example" = "257571"}, - * {"name" = "lang", "in" = "query", "description" = "Language of result", "type" = "string", "enum" = {"de", "en"}, "example" = "de"} + * {"name" = "lang", "in" = "query", "description" = "Language of result", "type" = "string", "enum" = {"de", "en"}, "example" = "de"}, + * {"name" = "include", "in" = "query", "description" = "Optional resources to include ", "type" = "string", "example" = "localData"} * } * } * } diff --git a/src/Entity/CourseTrait.php b/src/Entity/CourseTrait.php index b36d1f0..32193d5 100644 --- a/src/Entity/CourseTrait.php +++ b/src/Entity/CourseTrait.php @@ -6,6 +6,7 @@ namespace Dbp\Relay\BaseCourseBundle\Entity; use ApiPlatform\Core\Annotation\ApiProperty; use Symfony\Component\Serializer\Annotation\Groups; +use Symfony\Component\Serializer\Annotation\Ignore; trait CourseTrait { @@ -86,23 +87,32 @@ trait CourseTrait $this->description = $description; } + public function getLocalData(): array + { + return $this->localData; + } + /** * Allows attaching local data to a Course object. * * @param ?mixed $value */ - public function setLocalData(string $key, $value): void + public function setLocalDataValue(string $key, $value): void { + if (!$this->localData) { + $this->localData = []; + } $this->localData[$key] = $value; } /** + * @Ignore * Gets local data from a Course object. * * @return ?mixed */ - public function getLocalData(string $key) + public function getLocalDataValue(string $key) { - return $this->localData[$key] ?? null; + return $this->localData ? ($this->localData[$key] ?? null) : null; } } diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index a725920..ed2c03d 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -9,6 +9,11 @@ services: autowire: true autoconfigure: true +# Dbp\Relay\BaseCourseBundle\Serializer\Normalizer\CourseNormalizer: +# autowire: true +# autoconfigure: true +# tags: ['serializer.normalizer'] + Dbp\Relay\BaseCourseBundle\Service\DummyCourseProvider: autowire: true autoconfigure: true diff --git a/src/Serializer/Normalizer/CourseNormalizer.php b/src/Serializer/Normalizer/CourseNormalizer.php new file mode 100644 index 0000000..d9d69fc --- /dev/null +++ b/src/Serializer/Normalizer/CourseNormalizer.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace Dbp\Relay\BaseCourseBundle\Serializer\Normalizer; + +use Dbp\Relay\BaseCourseBundle\Entity\Course; +use Symfony\Component\Serializer\Exception\ExceptionInterface; +use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; + +class CourseNormalizer implements ContextAwareNormalizerInterface, NormalizerAwareInterface +{ + use NormalizerAwareTrait; + + private const ALREADY_CALLED = 'COURSE_NORMALIZER_CURRENT_USER_ALREADY_CALLED'; + + /** + * @return array|string|int|float|bool|\ArrayObject|null + * + * @throws ExceptionInterface + */ + public function normalize($object, $format = null, array $context = []) + { + // TODO: only add localData group if it is requested? + // problem: $context['filters'] not available at this point + $context['groups'][] = 'BaseCourse:localData'; + $context[self::ALREADY_CALLED] = true; + + return $this->normalizer->normalize($object, $format, $context); + } + + public function supportsNormalization($data, $format = null, array $context = []): bool + { + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + + return $data instanceof Course; + } +} -- GitLab