Skip to content

Commit

Permalink
Added the LocationGuesser API that guesses a location from a content
Browse files Browse the repository at this point in the history
  • Loading branch information
Bertrand Dunogier committed Nov 25, 2020
1 parent 1d14444 commit 35c4fef
Show file tree
Hide file tree
Showing 11 changed files with 482 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public function load(array $configs, ContainerBuilder $container)

$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services/data_loaders.yaml');
$loader->load('services/location_guesser.yaml');
$loader->load('services/mutations.yaml');
$loader->load('services/resolvers.yaml');
$loader->load('services/schema.yaml');
Expand Down
55 changes: 55 additions & 0 deletions src/Exception/MultipleValidLocationsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?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 eZ\Publish\API\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\Location;

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

/**
* @var \eZ\Publish\API\Repository\Values\Content\Content
*/
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. 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;
}
}
36 changes: 36 additions & 0 deletions src/Exception/NoValidLocationsException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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;
}
}
56 changes: 56 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/FilterLocationGuesser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?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;

/**
* 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());
}
}
20 changes: 20 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/LocationFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?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;

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;
}
50 changes: 50 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/LocationGuess.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?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;

class LocationGuess
{
private $content;

private $locations;

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

/**
* 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 function getLocation(): Location
{
if (count($this->locations) > 1) {
throw new Exception\MultipleValidLocationsException($this->content, $this->locations);
} elseif (count($this->locations) === 0) {
throw new NoValidLocationsException($this->content);
}

return $this->locations[0];
}

public function isSuccessful(): bool
{
return count($this->locations) === 1;
}
}
22 changes: 22 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/LocationGuesser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?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 LocationGuesser
{
/**
* Tries to guess a valid location for a content item.
*
* @param \eZ\Publish\API\Repository\Values\Content\Content $content
*
* @return LocationGuess
*/
public function guessLocation(Content $content): LocationGuess;
}
76 changes: 76 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/LocationList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?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;
use EzSystems\EzPlatformGraphQL\Exception;
use SplObjectStorage;

/**
* The result of the guesser's work.
*/
class LocationList
{
/**
* The content item locations were guessed for.
*
* @var \eZ\Publish\API\Repository\Values\Content\Content
*/
private $content;

/**
* @var \SplObjectStorage
*/
private $locations;

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

public function addLocation(Location $location)
{
$this->locations->attach($location);
}

/**
* @return \eZ\Publish\API\Repository\Values\Content\Location
*
* @throws \EzSystems\EzPlatformGraphQL\Exception\MultipleValidLocationsException
* @throws \EzSystems\EzPlatformGraphQL\Exception\NoValidLocationsException
*/
public function getLocation(): Location
{
if (count($this->locations) === 1) {
return current($this->locations);
} elseif (count($this->locations) > 1) {
throw new Exception\MultipleValidLocationsException($this->content, \iterator_to_array($this->locations));
} elseif (count($this->locations) === 0) {
throw new Exception\NoValidLocationsException($this->content);
}
}

public function getLocations(): array
{
return \iterator_to_array($this->locations);
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Location $location
*/
public function hasOneLocation(): bool
{
return count($this->locations) === 1;
}

public function filter(Location $location)
{
$this->locations->detach($location);
}
}
26 changes: 26 additions & 0 deletions src/GraphQL/Resolver/LocationGuesser/MainLocationFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?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;

/**
* Selects a location, if there are several, by picking the main one if it is part of the current tree root.
*/
class MainLocationFilter implements LocationFilter
{
public function filter(Content $content, LocationList $locationList): void
{
foreach ($locationList->getLocations() as $location) {
if ($location->id !== $content->contentInfo->mainLocationId) {
$locationList->filter($location);
}
}
}
}
Loading

0 comments on commit 35c4fef

Please sign in to comment.