diff --git a/composer.json b/composer.json index 109adf8dcbe49517e4b0d15157d935090b0db285..4b850020f0cc6a93f6b034216ebda598fbf1e7d8 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "php": ">=7.3", "ext-json": "*", "api-platform/core": "^2.6", - "dbp/relay-core-bundle": "^0.1.35", + "dbp/relay-core-bundle": "dev-main as 0.1.36", "symfony/config": "^5.4", "symfony/framework-bundle": "^5.4", "symfony/security-bundle": "^5.4", diff --git a/composer.lock b/composer.lock index dcfb675be7291afdd4f2120d91b5d565fdfc78e9..396aeca9e703cd941a128e1fe32f2a87503c722a 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": "fd4590971a60339582f751c46725be9f", + "content-hash": "2ca7ac7fd502090cb757d89983e9bdb7", "packages": [ { "name": "api-platform/core", @@ -169,17 +169,11 @@ }, { "name": "dbp/relay-core-bundle", - "version": "v0.1.36", + "version": "dev-main", "source": { "type": "git", - "url": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-core-bundle.git", - "reference": "e271903213daaf1ae2b1f144ac39df05bf6627cc" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.tugraz.at/api/v4/projects/dbp%2Frelay%2Fdbp-relay-core-bundle/repository/archive.zip?sha=e271903213daaf1ae2b1f144ac39df05bf6627cc", - "reference": "e271903213daaf1ae2b1f144ac39df05bf6627cc", - "shasum": "" + "url": "git@gitlab.tugraz.at:dbp/relay/dbp-relay-core-bundle.git", + "reference": "8d46b8ae30a35a0853335ea550b03287fc5a21e8" }, "require": { "api-platform/core": "^2.6.6", @@ -221,6 +215,7 @@ "symfony/phpunit-bridge": "^5.3", "vimeo/psalm": "^4.4" }, + "default-branch": true, "type": "symfony-bundle", "extra": { "hooks": { @@ -274,11 +269,7 @@ "AGPL-3.0-or-later" ], "description": "The core bundle of the Relay API gateway", - "support": { - "source": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-core-bundle/-/tree/v0.1.36", - "issues": "https://gitlab.tugraz.at/dbp/relay/dbp-relay-core-bundle/-/issues" - }, - "time": "2022-05-11T10:49:59+02:00" + "time": "2022-06-02T08:07:57+00:00" }, { "name": "doctrine/annotations", @@ -10042,9 +10033,18 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "dbp/relay-core-bundle", + "version": "dev-main", + "alias": "0.1.36", + "alias_normalized": "0.1.36.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "dbp/relay-core-bundle": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -10055,5 +10055,5 @@ "platform-overrides": { "php": "7.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.2.0" } diff --git a/src/API/CourseProviderInterface.php b/src/API/CourseProviderInterface.php index b08634d29ffc278719c98017cc38399b3282a4ae..da917ad57917d97f78e522ae521a73c2bb436b34 100644 --- a/src/API/CourseProviderInterface.php +++ b/src/API/CourseProviderInterface.php @@ -5,8 +5,8 @@ declare(strict_types=1); namespace Dbp\Relay\BaseCourseBundle\API; use Dbp\Relay\BaseCourseBundle\Entity\Course; -use Dbp\Relay\BaseCourseBundle\Entity\CourseAttendee; use Dbp\Relay\CoreBundle\Exception\ApiError; +use Dbp\Relay\CoreBundle\Pagination\Paginator; interface CourseProviderInterface { @@ -16,30 +16,22 @@ interface CourseProviderInterface public function getCourseById(string $identifier, array $options = []): Course; /** - * @return Course[] - * * @throws ApiError */ - public function getCourses(array $options = []): array; + public function getCourses(array $options = []): Paginator; /** - * @return Course[] - * * @throws ApiError */ - public function getCoursesByOrganization(string $orgUnitId, array $options = []): array; + public function getCoursesByOrganization(string $orgUnitId, array $options = []): Paginator; /** - * @return Course[] - * * @throws ApiError */ - public function getCoursesByLecturer(string $lecturerId, array $options = []): array; + public function getCoursesByLecturer(string $lecturerId, array $options = []): Paginator; /** - * @return CourseAttendee[] - * * @throws ApiError */ - public function getAttendeesByCourse(string $courseId, array $options = []): array; + public function getAttendeesByCourse(string $courseId, array $options = []): Paginator; } diff --git a/src/DataProvider/CourseCollectionDataProvider.php b/src/DataProvider/CourseCollectionDataProvider.php index 5e904e201a196541372fb15672a1d754a9eef3c2..b44a363f830450175a629a33daf21a588424bdcd 100644 --- a/src/DataProvider/CourseCollectionDataProvider.php +++ b/src/DataProvider/CourseCollectionDataProvider.php @@ -8,17 +8,22 @@ use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface; use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface; use Dbp\Relay\BaseCourseBundle\API\CourseProviderInterface; use Dbp\Relay\BaseCourseBundle\Entity\Course; -use Dbp\Relay\CoreBundle\Helpers\ArrayFullPaginator; use Dbp\Relay\CoreBundle\LocalData\LocalData; +use Dbp\Relay\CoreBundle\Pagination\Pagination; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; final class CourseCollectionDataProvider extends AbstractController implements CollectionDataProviderInterface, RestrictedDataProviderInterface { + /** @var CourseProviderInterface */ private $courseProvider; - public function __construct(CourseProviderInterface $courseProvider) + /** @var Pagination */ + private $pagination; + + public function __construct(CourseProviderInterface $courseProvider, Pagination $pagination) { $this->courseProvider = $courseProvider; + $this->pagination = $pagination; } public function supports(string $resourceClass, string $operationName = null, array $context = []): bool @@ -26,7 +31,7 @@ final class CourseCollectionDataProvider extends AbstractController implements C return Course::class === $resourceClass; } - public function getCollection(string $resourceClass, string $operationName = null, array $context = []): ArrayFullPaginator + public function getCollection(string $resourceClass, string $operationName = null, array $context = []): iterable { $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); @@ -35,45 +40,50 @@ final class CourseCollectionDataProvider extends AbstractController implements C $options = []; $options['lang'] = $filters['lang'] ?? 'de'; + if ($search = ($filters['search'] ?? null)) { + $options['search'] = $search; + } + if ($term = ($filters['term'] ?? null)) { $options['term'] = $term; } - $options[LocalData::INCLUDE_PARAMETER_NAME] = LocalData::getIncludeParameter($filters); + if ($includeParameter = LocalData::getIncludeParameter($filters)) { + $options[LocalData::INCLUDE_PARAMETER_NAME] = $includeParameter; + } - $organizationId = $filters['organization'] ?? null; - $lecturerId = $filters['lecturer'] ?? null; + $organizationId = $filters['organization'] ?? ''; + $lecturerId = $filters['lecturer'] ?? ''; - $courses = null; - if (!empty($organizationId) || !empty($lecturerId)) { - if (!empty($organizationId)) { - $courses = $this->courseProvider->getCoursesByOrganization($organizationId, $options); + $filterByOrganizationId = $organizationId !== ''; + $filterByLecturerId = $lecturerId !== ''; + + if (!($filterByOrganizationId && $filterByLecturerId)) { + $this->pagination->addPaginationOptions($options, $resourceClass, $operationName, $context); + } // else -> request the whole set of results + + $coursePaginator = null; + if ($filterByOrganizationId || $filterByLecturerId) { + if ($filterByOrganizationId) { + $coursePaginator = $this->courseProvider->getCoursesByOrganization($organizationId, $options); } - if (!empty($lecturerId)) { - $coursesByPerson = $this->courseProvider->getCoursesByLecturer($lecturerId, $options); - if (!empty($organizationId)) { - $courses = array_uintersect($courses, $coursesByPerson, - 'Dbp\Relay\BaseCourseBundle\DataProvider\CourseCollectionDataProvider::compareCourses'); - $courses = array_values($courses); + if ($filterByLecturerId) { + $coursesByPersonPaginator = $this->courseProvider->getCoursesByLecturer($lecturerId, $options); + + if (!$filterByOrganizationId) { + $coursePaginator = $coursesByPersonPaginator; } else { - $courses = $coursesByPerson; + $intersection = array_uintersect($coursePaginator->getItems(), $coursesByPersonPaginator->getItems(), + 'Dbp\Relay\BaseCourseBundle\DataProvider\CourseCollectionDataProvider::compareCourses'); + $courses = array_values($intersection); + $coursePaginator = $this->pagination->createWholeResultPaginator($courses, $resourceClass, $operationName, $context); } } } else { - $courses = $this->courseProvider->getCourses($options); - } - - $page = 1; - if (isset($filters['page'])) { - $page = (int) $filters['page']; - } - - $perPage = 30; - if (isset($filters['perPage'])) { - $perPage = (int) $filters['perPage']; + $coursePaginator = $this->courseProvider->getCourses($options); } - return new ArrayFullPaginator($courses, $page, $perPage); + return $coursePaginator ?? []; } public static function compareCourses(Course $a, Course $b): int diff --git a/src/Entity/Course.php b/src/Entity/Course.php index 07071fe6abecc1baf746461bbacab69b3ae83459..25147fa64ea9306aa5c11a49fef078fac27d523a 100644 --- a/src/Entity/Course.php +++ b/src/Entity/Course.php @@ -16,6 +16,7 @@ use Dbp\Relay\CoreBundle\LocalData\LocalDataAwareTrait; * "openapi_context" = { * "tags" = {"BaseCourse"}, * "parameters" = { + * {"name" = "search", "in" = "query", "description" = "Search for a course", "type" = "string", "required" = false}, * {"name" = "lang", "in" = "query", "description" = "Language of result", "type" = "string", "enum" = {"de", "en"}, "example" = "de"}, * {"name" = "term", "in" = "query", "description" = "Teaching term", "type" = "string", "enum" = {"W", "S"}, "example" = "W"}, * {"name" = "organization", "in" = "query", "description" = "Get courses of an organization (ID of BaseOrganization resource)", "required" = false, "type" = "string", "example" = "1190"}, diff --git a/src/Service/DummyCourseProvider.php b/src/Service/DummyCourseProvider.php index 2de0a9dad1661ec1c794be3a5d3f982a04045926..ac7ec3a8567503d0421c05517077df30ff8eb7c6 100644 --- a/src/Service/DummyCourseProvider.php +++ b/src/Service/DummyCourseProvider.php @@ -7,6 +7,8 @@ namespace Dbp\Relay\BaseCourseBundle\Service; use Dbp\Relay\BaseCourseBundle\API\CourseProviderInterface; use Dbp\Relay\BaseCourseBundle\Entity\Course; use Dbp\Relay\BaseCourseBundle\Entity\CourseAttendee; +use Dbp\Relay\CoreBundle\Pagination\FullPaginator; +use Dbp\Relay\CoreBundle\Pagination\Paginator; class DummyCourseProvider implements CourseProviderInterface { @@ -19,20 +21,20 @@ class DummyCourseProvider implements CourseProviderInterface return $course; } - public function getCourses(array $options = []): array + public function getCourses(array $options = []): Paginator { - $course = $this->getCourseById('123', $options); - assert($course !== null); + $courses = []; + $courses[] = $this->getCourseById('123', $options); - return [$course]; + return new FullPaginator($courses, 1, count($courses), count($courses)); } - public function getCoursesByOrganization(string $orgUnitId, array $options = []): array + public function getCoursesByOrganization(string $orgUnitId, array $options = []): Paginator { return $this->getCourses($options); } - public function getAttendeesByCourse(string $courseId, array $options = []): array + public function getAttendeesByCourse(string $courseId, array $options = []): Paginator { $attendee = new CourseAttendee(); $attendee->setIdentifier('aeinstein'); @@ -40,10 +42,10 @@ class DummyCourseProvider implements CourseProviderInterface $attendee->setFamilyName('Einstein'); $attendee->setEmail('info@einstein.com'); - return [$attendee]; + return new FullPaginator($attendees = [$attendee], 1, count($attendees), count($attendees)); } - public function getCoursesByLecturer(string $lecturerId, array $options = []): array + public function getCoursesByLecturer(string $lecturerId, array $options = []): Paginator { return $this->getCourses($options); }