From 0102724b1e3271e0a2faae91a42b7d50a6ebdedb Mon Sep 17 00:00:00 2001 From: Bertrand Dunogier Date: Fri, 27 Nov 2020 16:28:42 +0100 Subject: [PATCH] Improved the LocationGuesser API to be usable for relations as well Two ItemFactory instances are exposed, depending on the need: - $siteItemFactory: locations and aliases are within the current site root only - $relatedItemFactory: locations and aliases can be in other public siteaccesses / site roots --- .../AllAllowedLocationProvider.php | 39 ++++++++++++++ .../CurrentSiteLocationProvider.php | 53 +++++++++++++++++++ .../LocationGuesser/FilterLocationGuesser.php | 34 ++++++------ .../LocationGuesser/LocationGuesser.php | 1 - .../Resolver/LocationGuesser/LocationList.php | 3 ++ .../LocationGuesser/LocationProvider.php | 14 +++++ .../Resolver/RelationFieldResolver.php | 6 +-- src/GraphQL/Value/Item.php | 8 ++- .../config/services/location_guesser.yaml | 16 ++++-- src/Resources/config/services/services.yaml | 14 ++++- 10 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 src/GraphQL/Resolver/LocationGuesser/AllAllowedLocationProvider.php create mode 100644 src/GraphQL/Resolver/LocationGuesser/CurrentSiteLocationProvider.php create mode 100644 src/GraphQL/Resolver/LocationGuesser/LocationProvider.php diff --git a/src/GraphQL/Resolver/LocationGuesser/AllAllowedLocationProvider.php b/src/GraphQL/Resolver/LocationGuesser/AllAllowedLocationProvider.php new file mode 100644 index 00000000..7018bf03 --- /dev/null +++ b/src/GraphQL/Resolver/LocationGuesser/AllAllowedLocationProvider.php @@ -0,0 +1,39 @@ +locationService = $locationService; + } + + public function getLocations(Content $content): LocationList + { + $list = new LocationList($content); + + foreach ($this->locationService->loadLocations($content->contentInfo) as $location) { + $list->addLocation($location); + } + + return $list; + } +} diff --git a/src/GraphQL/Resolver/LocationGuesser/CurrentSiteLocationProvider.php b/src/GraphQL/Resolver/LocationGuesser/CurrentSiteLocationProvider.php new file mode 100644 index 00000000..5dd0e8a2 --- /dev/null +++ b/src/GraphQL/Resolver/LocationGuesser/CurrentSiteLocationProvider.php @@ -0,0 +1,53 @@ +searchService = $searchService; + $this->filterBuilder = $filterBuilder; + } + + public function getLocations(Content $content): LocationList + { + $query = new LocationQuery([ + 'filter' => new Criterion\LogicalAnd([ + $this->filterBuilder->buildFilter(), + new Criterion\ContentId($content->id), + ]), + ]); + + $list = new LocationList($content); + foreach ($this->searchService->findLocations($query)->searchHits as $searchHit) { + $list->addLocation($searchHit->valueObject); + } + + return $list; + } +} diff --git a/src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php b/src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php index 1281abf6..dc49e5a3 100644 --- a/src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php +++ b/src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php @@ -4,14 +4,14 @@ * @copyright Copyright (C) eZ Systems AS. All rights reserved. * @license For full copyright and license information view LICENSE file distributed with this source code. */ +declare(strict_types=1); + namespace EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser; -use eZ\Publish\API\Repository\LocationService; use eZ\Publish\API\Repository\Values\Content\Content; -use eZ\Publish\API\Repository\Values\Content\Location; /** - * Guesses a location based on voters. + * Guesses locations for a site by filtering out a provided list. */ class FilterLocationGuesser implements LocationGuesser { @@ -21,17 +21,14 @@ class FilterLocationGuesser implements LocationGuesser private $filters; /** - * @var \eZ\Publish\API\Repository\LocationService + * @var \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationProvider */ - private $locationService; + private $provider; - /** - * @param LocationFilter[] $filters - */ - public function __construct(LocationService $locationService, array $filters) + public function __construct(LocationProvider $provider, array $filters) { + $this->provider = $provider; $this->filters = $filters; - $this->locationService = $locationService; } /** @@ -39,15 +36,14 @@ public function __construct(LocationService $locationService, array $filters) */ public function guessLocation(Content $content): LocationGuess { - $locationList = new LocationList($content); - foreach ($this->locationService->loadLocations($content->contentInfo) as $location) { - $locationList->addLocation($location); - } - - foreach ($this->filters as $filter) { - $filter->filter($content, $locationList); - if ($locationList->hasOneLocation()) { - return new LocationGuess($content, $locationList->getLocations()); + $locationList = $this->provider->getLocations($content); + + if (!$locationList->hasOneLocation()) { + foreach ($this->filters as $filter) { + $filter->filter($content, $locationList); + if ($locationList->hasOneLocation()) { + return new LocationGuess($content, $locationList->getLocations()); + } } } diff --git a/src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php b/src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php index b7d18e0b..fab685ff 100644 --- a/src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php +++ b/src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php @@ -7,7 +7,6 @@ namespace EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser; use eZ\Publish\API\Repository\Values\Content\Content; -use eZ\Publish\API\Repository\Values\Content\Location; interface LocationGuesser { diff --git a/src/GraphQL/Resolver/LocationGuesser/LocationList.php b/src/GraphQL/Resolver/LocationGuesser/LocationList.php index ca75d076..d2665e08 100644 --- a/src/GraphQL/Resolver/LocationGuesser/LocationList.php +++ b/src/GraphQL/Resolver/LocationGuesser/LocationList.php @@ -56,6 +56,9 @@ public function getLocation(): Location } } + /** + * @return \eZ\Publish\API\Repository\Values\Content\Location[] + */ public function getLocations(): array { return \iterator_to_array($this->locations); diff --git a/src/GraphQL/Resolver/LocationGuesser/LocationProvider.php b/src/GraphQL/Resolver/LocationGuesser/LocationProvider.php new file mode 100644 index 00000000..3683db76 --- /dev/null +++ b/src/GraphQL/Resolver/LocationGuesser/LocationProvider.php @@ -0,0 +1,14 @@ +contentLoader = $contentLoader; - $this->itemFactory = $itemFactory; + $this->itemFactory = $relatedContentItemFactory; } public function resolveRelationFieldValue(Field $field, $multiple = false) @@ -35,8 +35,6 @@ public function resolveRelationFieldValue(Field $field, $multiple = false) return $multiple ? [] : null; } - // @todo do we want to restrict results to the current siteaccess (tree root) ? - // What if the user has access to locations from other siteaccesses ? $contentItems = $this->contentLoader->find(new Query( ['filter' => new Query\Criterion\ContentId($destinationContentIds)] )); diff --git a/src/GraphQL/Value/Item.php b/src/GraphQL/Value/Item.php index a3b474d1..c7fb73a4 100644 --- a/src/GraphQL/Value/Item.php +++ b/src/GraphQL/Value/Item.php @@ -11,8 +11,10 @@ use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; use eZ\Publish\Core\MVC\Symfony\SiteAccess; +use EzSystems\EzPlatformGraphQL\Exception\NoValidLocationsException; use EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser; use EzSystems\EzPlatformGraphQL\GraphQL\Resolver\SiteaccessGuesser\SiteaccessGuesser; +use Overblog\GraphQLBundle\Error\UserError; /** * A DXP item, combination of a Content and Location. @@ -57,7 +59,11 @@ public function getContent(): Content public function getLocation(): Location { if ($this->location === null) { - $this->location = $this->locationGuesser->guessLocation($this->content)->getLocation(); + try { + $this->location = $this->locationGuesser->guessLocation($this->content)->getLocation(); + } catch (NoValidLocationsException $e) { + throw new UserError($e->getMessage(), 0, $e); + } } return $this->location; diff --git a/src/Resources/config/services/location_guesser.yaml b/src/Resources/config/services/location_guesser.yaml index bdd2395b..c3004d9c 100644 --- a/src/Resources/config/services/location_guesser.yaml +++ b/src/Resources/config/services/location_guesser.yaml @@ -8,10 +8,20 @@ services: EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\MainLocationFilter: ~ - EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser: - class: 'EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\FilterLocationGuesser' + EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\CurrentSiteLocationProvider: ~ + + EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\AllAllowedLocationProvider: ~ + + EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser\CurrentSiteContent: + class: EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\FilterLocationGuesser arguments: + $provider: '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\CurrentSiteLocationProvider' $filters: - - '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\TreeRootLocationFilter' - '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\MainLocationFilter' + EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser\RelatedContent: + class: EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\FilterLocationGuesser + arguments: + $provider: '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\AllAllowedLocationProvider' + $filters: + - '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\MainLocationFilter' diff --git a/src/Resources/config/services/services.yaml b/src/Resources/config/services/services.yaml index 2b0273e3..c11fe8c3 100644 --- a/src/Resources/config/services/services.yaml +++ b/src/Resources/config/services/services.yaml @@ -17,7 +17,19 @@ services: arguments: $siteAccessGroups: '%ezpublish.siteaccess.groups%' - EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory: ~ + EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory $currentSiteItemFactory: '@EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory\CurrentSite' + + EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory $relatedContentItemFactory: '@EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory\RelatedContent' + + EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory\CurrentSite: + class: 'EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory' + arguments: + $locationGuesser: '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser\CurrentSiteContent' + + EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory\RelatedContent: + class: 'EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory' + arguments: + $locationGuesser: '@EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser\RelatedContent' EzSystems\EzPlatformGraphQL\GraphQL\Resolver\SiteaccessGuesser\SiteaccessGuesser: arguments: