Skip to content

Commit

Permalink
Re-architectured the location guesser API
Browse files Browse the repository at this point in the history
  • Loading branch information
Bertrand Dunogier committed Nov 24, 2020
1 parent 4317f51 commit 84392e6
Show file tree
Hide file tree
Showing 16 changed files with 382 additions and 77 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
Expand All @@ -8,32 +7,48 @@

namespace EzSystems\EzPlatformGraphQL\Exception;

use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;

class MultiplePossibleLocationsException extends \Exception
class MultipleValidLocationsException extends \Exception
{
/**
* @var Location[]
* @var \eZ\Publish\API\Repository\Values\Content\Location[]
*/
private $locations = [];

/**
* @param Location[] $locations
* @var \eZ\Publish\API\Repository\Values\Content\Content
*/
public function __construct(array $locations)
private $content;

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param \eZ\Publish\API\Repository\Values\Content\Location[] $locations
*/
public function __construct(Content $content, array $locations)
{
$this->locations = $locations;
parent::__construct(
sprintf(
'Could not determine which location to return for content with id %s (locations: %s)',
$locations[0]->contentId,
'Could not determine which location to return for content with id %s. Possible candidates: %s)',
$content->id,
implode(',', array_map(function (Location $location) { return $location->pathString; }, $locations))
)
);
$this->content = $content;
}

/**
* @return Location[]
*/
public function getLocations(): array
{
return $this->locations;
}

public function getContent(): Content
{
return $this->content;
}
}
19 changes: 0 additions & 19 deletions src/Exception/NoValidLocationFoundException.php

This file was deleted.

35 changes: 35 additions & 0 deletions src/Exception/NoValidLocationsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/**
* @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\Exception;

use Exception;
use eZ\Publish\API\Repository\Values\Content\Content;

class NoValidLocationsException extends Exception
{
/**
* @var \eZ\Publish\API\Repository\Values\Content\Content|\eZ\Publish\API\Repository\Values\Content\Content[]
*/
private $content;

/**
* NoValidLocationsException constructor.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
*/
public function __construct(Content $content)
{
parent::__construct("No valid location could be determined for content #{$content->id}");
$this->content = $content;
}

public function getContent(): Content
{
return $this->content;
}
}
34 changes: 34 additions & 0 deletions src/GraphQL/ItemFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/

namespace EzSystems\EzPlatformGraphQL\GraphQL;

use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;
use EzSystems\EzPlatformGraphQL\GraphQL\Value\Item;

class ItemFactory
{
/**
* @var \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser
*/
private $locationGuesser;

public function __construct(Resolver\LocationGuesser\LocationGuesser $locationGuesser)
{
$this->locationGuesser = $locationGuesser;
}

public function fromContent(Content $content): Item
{
return new Item($this->locationGuesser, null, $content);
}

public function fromLocation(Location $location)
{
return new Item($this->locationGuesser, $location, null);
}
}
27 changes: 20 additions & 7 deletions src/GraphQL/Resolver/DomainContentResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use EzSystems\EzPlatformGraphQL\GraphQL\DataLoader\ContentTypeLoader;
use EzSystems\EzPlatformGraphQL\GraphQL\DataLoader\LocationLoader;
use EzSystems\EzPlatformGraphQL\GraphQL\InputMapper\SearchQueryMapper;
use EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory;
use EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser;
use EzSystems\EzPlatformGraphQL\GraphQL\Value\Field;
use EzSystems\EzPlatformGraphQL\GraphQL\Value\Item;
Expand Down Expand Up @@ -59,7 +60,12 @@ class DomainContentResolver
/**
* @var \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationGuesser
*/

private $locationGuesser;
/**
* @var \EzSystems\EzPlatformGraphQL\GraphQL\ItemFactory
*/
private $itemFactory;

public function __construct(
Repository $repository,
Expand All @@ -68,7 +74,8 @@ public function __construct(
ContentLoader $contentLoader,
ContentTypeLoader $contentTypeLoader,
LocationLoader $locationLoader,
LocationGuesser $locationGuesser
LocationGuesser $locationGuesser,
ItemFactory $itemFactory
) {
$this->repository = $repository;
$this->typeResolver = $typeResolver;
Expand All @@ -77,6 +84,7 @@ public function __construct(
$this->contentTypeLoader = $contentTypeLoader;
$this->locationLoader = $locationLoader;
$this->locationGuesser = $locationGuesser;
$this->itemFactory = $itemFactory;
}

public function resolveDomainContentItems($contentTypeIdentifier, $query = null)
Expand Down Expand Up @@ -138,13 +146,10 @@ public function resolveItem($args, $contentTypeIdentifier): Item
{
if (isset($args['id'])) {
$content = $this->contentLoader->findSingle(new Query\Criterion\ContentId($args['id']));
$location = $this->locationGuesser->guessLocation($content)->location;
} elseif (isset($args['contentId'])) {
$content = $this->contentLoader->findSingle(new Query\Criterion\ContentId($args['contentId']));
$location = $this->locationGuesser->guessLocation($content)->location;
} elseif (isset($args['remoteId'])) {
$content = $this->contentLoader->findSingle(new Query\Criterion\RemoteId($args['remoteId']));
$location = $this->locationGuesser->guessLocation($content)->location;
} elseif (isset($args['locationId'])) {
$location = $this->locationLoader->findById($args['locationId']);
} elseif (isset($args['locationRemoteId'])) {
Expand All @@ -155,13 +160,21 @@ public function resolveItem($args, $contentTypeIdentifier): Item
throw new UserError('Missing required argument id, remoteId or locationId');
}

$contentType = $location->getContentInfo()->getContentType();
if (isset($content)) {
$item = $this->itemFactory->fromContent($content);
} else if (isset($location)) {
$item = $this->itemFactory->fromLocation($location);
} else {
throw new \Exception("One of 'location' or 'content' must be defined");
}

$contentType = $item->getContentInfo()->getContentType();

if (null !== $contentTypeIdentifier && $contentType->identifier !== $contentTypeIdentifier) {
throw new UserError("Content {$location->getContentInfo()->id} is not of type '$contentTypeIdentifier'");
throw new UserError("Content {$item->getContentInfo()->id} is not of type '$contentTypeIdentifier'");
}

return new Item($location);
return $item;
}

/**
Expand Down
58 changes: 58 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/


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;
use EzSystems\EzPlatformGraphQL\Exception\MultipleValidLocationsException;

/**
* Guesses a location based on voters.
*/
class FilterLocationGuesser implements LocationGuesser
{
/**
* @var \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationFilter[]
*/
private $filters;

/**
* @var \eZ\Publish\API\Repository\LocationService
*/
private $locationService;

/**
* @param LocationFilter[] $filters
*/
public function __construct(LocationService $locationService, array $filters)
{
$this->filters = $filters;
$this->locationService = $locationService;
}

/**
* @inheritDoc
*/
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());
}
}

return new LocationGuess($content, $locationList->getLocations());
}
}
21 changes: 21 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/LocationFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser;

use eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;

interface LocationFilter
{
/**
* Given a Content and a LocationList, filters out locations.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
* @param \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\LocationList $locationList
*/
public function filter(Content $content, LocationList $locationList): void;
}
40 changes: 32 additions & 8 deletions src/GraphQL/Resolver/LocationGuesser/LocationGuess.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
<?php

/**
* @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\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;
use EzSystems\EzPlatformGraphQL\Exception;

/**
* The result of the guesser's work.
*/
class LocationGuess
{
private $content;

private $locations;

public function __construct(Content $content, array $locations)
{
$this->content = $content;
$this->locations = $locations;
}

/**
* @var Location
* Returns the location guess result if the guess was successful.
*
* @return \eZ\Publish\API\Repository\Values\Content\Location
*
* @throws \EzSystems\EzPlatformGraphQL\Exception\MultipleValidLocationsException
* @throws \EzSystems\EzPlatformGraphQL\GraphQL\Resolver\LocationGuesser\NoValidLocationsException
*/
public $location;
public function getLocation(): Location
{
if (count($this->locations) > 1) {
throw new Exception\MultipleValidLocationsException($this->content, $this->locations);
} else if (count($this->locations) === 0) {
throw new NoValidLocationsException($this->content);
}

return $this->locations[0];
}

public function __construct(Location $location)
public function isSuccessful(): bool
{
$this->location = $location;
return count($this->locations) === 1;
}
}
8 changes: 2 additions & 6 deletions src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,11 @@
interface LocationGuesser
{
/**
* Given a Content item, returns a location.
* Tries to guess a valid location for a content item.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
*
* @return \eZ\Publish\API\Repository\Values\Content\Location
*
* @throws \EzSystems\EzPlatformGraphQL\Exception\NoValidLocationFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\BadStateException
* @throws \EzSystems\EzPlatformGraphQL\Exception\MultiplePossibleLocationsException
* @return LocationGuess
*/
public function guessLocation(Content $content): LocationGuess;
}
Loading

0 comments on commit 84392e6

Please sign in to comment.