Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EZP-30414: Relation fields aren't resolved #30

Merged
merged 3 commits into from
Apr 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

namespace spec\EzSystems\EzPlatformGraphQL\GraphQL\Resolver;

use eZ\Publish\SPI\Persistence\Content\Type\Handler as ContentTypeHandler;
use eZ\Publish\Core\Repository\Values\Content\Content;
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
use eZ\Publish\API\Repository\Values\Content\Query;
use EzSystems\EzPlatformGraphQL\GraphQL\DataLoader\ContentLoader;
use EzSystems\EzPlatformGraphQL\GraphQL\DataLoader\ContentTypeLoader;
use EzSystems\EzPlatformGraphQL\GraphQL\InputMapper\SearchQueryMapper;
use EzSystems\EzPlatformGraphQL\GraphQL\Resolver\DomainContentResolver;
use eZ\Publish\API\Repository\Repository;
use eZ\Publish\Core\FieldType;
use EzSystems\EzPlatformGraphQL\GraphQL\Value\Field;
use Overblog\GraphQLBundle\Resolver\TypeResolver;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class DomainContentResolverSpec extends ObjectBehavior
{
const CONTENT_ID = 1;

function let(
Repository $repository,
TypeResolver $typeResolver,
Expand All @@ -27,4 +35,110 @@ function it_is_initializable()
{
$this->shouldHaveType(DomainContentResolver::class);
}

function it_resolves_a_RelationList_field_value_with_multiple_to_an_array(ContentLoader $contentLoader)
{
$contentArray = $this->createContentList([self::CONTENT_ID]);
$field = $this->createRelationListField($contentArray);

$contentLoader->find($this->createContentIdListQuery($contentArray))->willReturn($contentArray);
$this->resolveDomainRelationFieldValue($field, true)->shouldReturn($contentArray);
}

function it_resolves_an_empty_RelationList_field_value_with_multiple_to_an_empty_array(ContentLoader $contentLoader)
{
$contentArray = [];
$field = $this->createRelationListField($contentArray);

$contentLoader->find(Argument::any())->shouldNotBeCalled();
$this->resolveDomainRelationFieldValue($field, true)->shouldReturn([]);
}

function it_resolves_a_Relation_field_value_without_multiple_to_a_content_item(ContentLoader $contentLoader)
{
$content = $this->createContent(self::CONTENT_ID);
$field = $this->createRelationField($content);
$contentLoader->find($this->createContentIdListQuery([$content]))->willReturn([$content]);

$this->resolveDomainRelationFieldValue($field, false)->shouldReturn($content);
}

function it_resolves_an_empty_Relation_field_value_without_multiple_to_null(ContentLoader $contentLoader)
{
$field = $this->createEmptyRelationField();

$contentLoader->find(Argument::any())->shouldNotBeCalled();
$this->resolveDomainRelationFieldValue($field, false)->shouldReturn(null);

}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentList
* @return Field
*/
private function createRelationListField(array $contentList): Field
{
return new Field(['value' => new FieldType\RelationList\Value($this->extractContentIdList($contentList))]);
}

private function createRelationField(Content $content): Field
{
return new Field(['value' => new FieldType\Relation\Value($content->id ?? null)]);
}

private function createEmptyRelationField(): Field
{
return new Field(['value' => new FieldType\Relation\Value()]);
}

private function createContentIdListQuery(array $contentList)
{
return new Query(['filter' => new Query\Criterion\ContentId($this->extractContentIdList($contentList))]);
}

private function createContentIdQuery(Content $content): Query
{
return new Query(['filter' => new Query\Criterion\ContentId($content->id)]);
}

/**
* @param \eZ\Publish\API\Repository\Values\Content\Content[] $contentList
* @return array
*/
private function extractContentIdList(array $contentList): array
{
return array_map(
function (Content $content) {
return $content->id;
},
$contentList
);
}

/**
* @param int[] $contentIdList
* @return Content[]
*/
private function createContentList(array $contentIdList): array
{
return array_map(
function ($contentId) {
return $this->createContent($contentId);
},
$contentIdList
);
}

/**
* @param $contentId
* @return Content
*/
private function createContent($contentId): Content
{
return new Content([
'versionInfo' => new VersionInfo([
'contentInfo' => new ContentInfo(['id' => $contentId])
])
]);
}
}
41 changes: 25 additions & 16 deletions src/GraphQL/Resolver/DomainContentResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,17 @@ public function resolveDomainFieldValue(Content $content, $fieldDefinitionIdenti

public function resolveDomainRelationFieldValue(Field $field, $multiple = false)
{
if (!$field->value instanceof FieldType\RelationList\Value) {
throw new UserError("$field->fieldTypeIdentifier is not a RelationList field value");
}
$destinationContentIds = $this->getContentIds($field);

if ($multiple) {
if (count($field->value->destinationContentIds) > 0) {
return $this->contentLoader->find(new Query(
['filter' => new Query\Criterion\ContentId($field->value->destinationContentIds)]
));
} else {
return [];
}
} else {
return
isset($fieldValue->destinationContentIds[0])
? $this->contentLoader->findSingle(new Query\Criterion\ContentId($field->value->destinationContentIds[0]))
: null;
if (empty($destinationContentIds) || array_key_exists(0, $destinationContentIds) && is_null($destinationContentIds[0])) {
return $multiple ? [] : null;
}

$contentItems = $this->contentLoader->find(new Query(
['filter' => new Query\Criterion\ContentId($destinationContentIds)]
Copy link

@crosa7 crosa7 Apr 3, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this with Solr enabled and it will throw an exception when $destinationContentIds is an empty array, a suggestion would be to add the following before "$contentItems = ..."
if(empty($destinationContentIds)) { return $multiple ? [] : null; }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, very good remark @crosa7. It should be fixed now.

));

return $multiple ? $contentItems : $contentItems[0] ?? null;
}

public function resolveDomainContentType(Content $content)
Expand All @@ -177,4 +170,20 @@ private function getLocationService()
{
return $this->repository->getLocationService();
}

/**
* @param \EzSystems\EzPlatformGraphQL\GraphQL\Value\Field $field
* @return array
* @throws UserError if the field isn't a Relation or RelationList value
*/
private function getContentIds(Field $field)
{
if ($field->value instanceof FieldType\RelationList\Value) {
return $field->value->destinationContentIds;
} else if ($field->value instanceof FieldType\Relation\Value) {
return [$field->value->destinationContentId];
} else {
throw new UserError('\$field does not contain a RelationList or Relation Field value');
}
}
}