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

IBX-3814: Added new endpoint to get field definition by identifier #99

Merged
merged 8 commits into from
Dec 14, 2022
8 changes: 8 additions & 0 deletions src/bundle/Resources/config/routing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,14 @@ ezpublish_rest_loadContentTypeFieldDefinition:
requirements:
contentTypeId: \d+
fieldDefinitionId: \d+

ibexa.rest.load_content_type_field_definition_by_identifier:
path: /content/types/{contentTypeId}/fieldDefinition/{fieldDefinitionIdentifier}
controller: ezpublish_rest.controller.content_type:loadContentTypeFieldDefinitionByIdentifier
methods: [GET]
requirements:
contentTypeId: \d+
fieldDefinitionIdentifier: \w+

ezpublish_rest_loadContentTypeDraft:
path: /content/types/{contentTypeId}/draft
Expand Down
32 changes: 32 additions & 0 deletions src/lib/Server/Controller/ContentType.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,38 @@ public function loadContentTypeFieldDefinition($contentTypeId, $fieldDefinitionI
throw new Exceptions\NotFoundException("Field definition not found: '{$request->getPathInfo()}'.");
}

/**
* @throws \EzSystems\EzPlatformRest\Exceptions\NotFoundException
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
*/
public function loadContentTypeFieldDefinitionByIdentifier(
int $contentTypeId,
string $fieldDefinitionIdentifier,
Request $request
): Values\RestFieldDefinition {
$contentType = $this->contentTypeService->loadContentType($contentTypeId);
$fieldDefinition = $contentType->getFieldDefinition($fieldDefinitionIdentifier);
$path = $this->router->generate(
'ibexa.rest.load_content_type_field_definition_by_identifier',
[
'contentTypeId' => $contentType->id,
'fieldDefinitionIdentifier' => $fieldDefinitionIdentifier,
]
);

if ($fieldDefinition === null) {
throw new Exceptions\NotFoundException(
sprintf("Field definition not found: '%s'.", $request->getPathInfo())
);
}

return new Values\RestFieldDefinition(
$contentType,
$fieldDefinition,
$path
);
}

/**
* Loads field definitions for a given content type draft.
*
Expand Down
14 changes: 8 additions & 6 deletions src/lib/Server/Output/ValueObjectVisitor/RestFieldDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,19 @@ public function visit(Visitor $visitor, Generator $generator, $data)
$visitor->setHeader('Accept-Patch', $generator->getMediaType('FieldDefinitionUpdate'));
}

$generator->startAttribute(
'href',
$this->router->generate(
if ($data->path === null) {
$href = $this->router->generate(
"ezpublish_rest_loadContentType{$urlTypeSuffix}FieldDefinition",
[
'contentTypeId' => $contentType->id,
'fieldDefinitionId' => $fieldDefinition->id,
]
)
);
$generator->endAttribute('href');
);
} else {
$href = $data->path;
}

$generator->attribute('href', $href);

$generator->startValueElement('id', $fieldDefinition->id);
$generator->endValueElement('id');
Expand Down
10 changes: 6 additions & 4 deletions src/lib/Server/Values/RestFieldDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ class RestFieldDefinition extends RestValue
public $fieldDefinition;

/**
* Construct.
* Path which is used to fetch the list of field definitions.
*
* @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
* @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition $fieldDefinition
* @var string|null
*/
public function __construct(ContentType $contentType, FieldDefinition $fieldDefinition)
public $path;
mateuszdebinski marked this conversation as resolved.
Show resolved Hide resolved

public function __construct(ContentType $contentType, FieldDefinition $fieldDefinition, ?string $path = null)
{
$this->contentType = $contentType;
$this->fieldDefinition = $fieldDefinition;
$this->path = $path;
}
}
23 changes: 23 additions & 0 deletions tests/bundle/Functional/ContentTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,29 @@ public function testLoadContentTypeFieldDefinition(string $fieldDefinitionHref)
self::assertHttpResponseCodeEquals($response, 200);
}

/**
* Covers GET /content/types/{contentTypeId}/fieldDefinition/{fieldDefinitionIdentifier}.
*
* @depends testCreateContentType
*
* @throws \Psr\Http\Client\ClientException
*/
public function testLoadContentTypeFieldDefinitionByIdentifier(string $contentTypeHref): void
{
$url = sprintf('%s/fieldDefinition/title', $contentTypeHref);

$response = $this->sendHttpRequest(
$this->createHttpRequest('GET', $url, '', 'FieldDefinition+json')
);

self::assertHttpResponseCodeEquals($response, 200);

$data = json_decode($response->getBody(), true);

self::assertEquals($url, $data['FieldDefinition']['_href']);
self::assertEquals('title', $data['FieldDefinition']['identifier']);
}

/**
* @depends testAddContentTypeDraftFieldDefinition
* Covers PATCH /content/types/<contentTypeId>/fieldDefinitions/<fieldDefinitionId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,24 @@ public function setUp(): void
$this->fieldTypeSerializerMock = $this->createMock(FieldTypeSerializer::class);
}

/**
* @return \DOMDocument
*/
public function testVisitRestFieldDefinition()
public function testVisitRestFieldDefinition(): \DOMDocument
{
return $this->generateDomDocument();
}

public function testVisitRestFieldDefinitionWithPath(): \DOMDocument
{
return $this->generateDomDocument('/content/types/contentTypeId/fieldDefinition/title');
}

protected function generateDomDocument(?string $path = null): \DOMDocument
{
$visitor = $this->getVisitor();
$generator = $this->getGenerator();

$generator->startDocument(null);

$restFieldDefinition = $this->getBasicRestFieldDefinition();
$restFieldDefinition = $this->getBasicRestFieldDefinition($path);

$this->fieldTypeSerializerMock->expects($this->once())
->method('serializeFieldDefaultValue')
Expand All @@ -43,14 +50,16 @@ public function testVisitRestFieldDefinition()
)
);

$this->addRouteExpectation(
'ezpublish_rest_loadContentTypeFieldDefinition',
[
'contentTypeId' => $restFieldDefinition->contentType->id,
'fieldDefinitionId' => $restFieldDefinition->fieldDefinition->id,
],
"/content/types/{$restFieldDefinition->contentType->id}/fieldDefinitions/{$restFieldDefinition->fieldDefinition->id}"
);
if ($path === null) {
$this->addRouteExpectation(
'ezpublish_rest_loadContentTypeFieldDefinition',
[
'contentTypeId' => $restFieldDefinition->contentType->id,
'fieldDefinitionId' => $restFieldDefinition->fieldDefinition->id,
],
"/content/types/{$restFieldDefinition->contentType->id}/fieldDefinitions/{$restFieldDefinition->fieldDefinition->id}"
);
}

$visitor->visit(
$this->getVisitorMock(),
Expand All @@ -68,7 +77,7 @@ public function testVisitRestFieldDefinition()
return $dom;
}

protected function getBasicRestFieldDefinition()
protected function getBasicRestFieldDefinition(?string $path = null): Server\Values\RestFieldDefinition
{
return new Server\Values\RestFieldDefinition(
new Values\ContentType\ContentType(
Expand All @@ -95,14 +104,40 @@ protected function getBasicRestFieldDefinition()
'names' => ['eng-US' => 'Sindelfingen'],
'descriptions' => ['eng-GB' => 'Bielefeld'],
]
)
),
$path
);
}

public function provideXpathAssertions(): array
{
$xpathAssertions = $this->getXpathAssertions();
$xpathAssertions[] = '/FieldDefinition[@href="/content/types/contentTypeId/fieldDefinitions/fieldDefinitionId_23"]';

return $this->prepareXPathAssertions($xpathAssertions);
}

public function provideXpathAssertionsPath(): array
{
$xpathAssertions = $this->getXpathAssertions();
$xpathAssertions[] = '/FieldDefinition[@href="/content/types/contentTypeId/fieldDefinition/title"]';

return $this->prepareXPathAssertions($xpathAssertions);
}

protected function prepareXPathAssertions(array $xpathAssertions): array
{
return array_map(
static function (string $xpath): array {
return [$xpath];
},
$xpathAssertions
);
}

public function provideXpathAssertions()
protected function getXpathAssertions(): array
{
$xpathAssertions = [
'/FieldDefinition[@href="/content/types/contentTypeId/fieldDefinitions/fieldDefinitionId_23"]',
return [
'/FieldDefinition[@media-type="application/vnd.ez.api.FieldDefinition+xml"]',
'/FieldDefinition/id[text()="fieldDefinitionId_23"]',
'/FieldDefinition/identifier[text()="title"]',
Expand All @@ -117,33 +152,30 @@ public function provideXpathAssertions()
'/FieldDefinition/names/value[@languageCode="eng-US" and text()="Sindelfingen"]',
'/FieldDefinition/descriptions/value[@languageCode="eng-GB" and text()="Bielefeld"]',
];

return array_map(
function ($xpath) {
return [$xpath];
},
$xpathAssertions
);
}

/**
* @param string $xpath
* @param \DOMDocument $dom
*
* @depends testVisitRestFieldDefinition
* @dataProvider provideXpathAssertions
*/
public function testGeneratedXml($xpath, \DOMDocument $dom)
public function testGeneratedXml(string $xpath, \DOMDocument $dom): void
{
$this->assertXPath($dom, $xpath);
}

/**
* @depends testVisitRestFieldDefinitionWithPath
* @dataProvider provideXpathAssertionsPath
*/
public function testGeneratedXmlPath(string $xpath, \DOMDocument $dom): void
{
$this->assertXPath($dom, $xpath);
}

/**
* Get the Content visitor.
*
* @return \EzSystems\EzPlatformRest\Server\Output\ValueObjectVisitor\RestFieldDefinition
*/
protected function internalGetVisitor()
protected function internalGetVisitor(): ValueObjectVisitor\RestFieldDefinition
{
return new ValueObjectVisitor\RestFieldDefinition($this->fieldTypeSerializerMock);
}
Expand Down