Skip to content
Open
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
52 changes: 52 additions & 0 deletions src/bundle/Controller/ContentTypeFieldsByExpressionController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\AdminUi\Controller;

use Ibexa\AdminUi\Exception\FieldTypeExpressionParserException;
use Ibexa\AdminUi\REST\Value\ContentType\FieldDefinitionInfoList;
use Ibexa\Contracts\AdminUi\ContentType\ContentTypeFieldsByExpressionServiceInterface;
use Ibexa\Rest\Message;
use Ibexa\Rest\Server\Controller as RestController;
use Ibexa\Rest\Server\Exceptions\BadRequestException;
use Symfony\Component\HttpFoundation\Request;

final class ContentTypeFieldsByExpressionController extends RestController
{
private ContentTypeFieldsByExpressionServiceInterface $fieldsByExpressionService;

public function __construct(ContentTypeFieldsByExpressionServiceInterface $fieldsByExpressionService)
{
$this->fieldsByExpressionService = $fieldsByExpressionService;
}

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
*/
public function loadFieldDefinitionsFromExpression(Request $request): FieldDefinitionInfoList
{
/** @var \Ibexa\AdminUi\REST\Value\ContentType\FieldDefinitionExpression $input */
$input = $this->inputDispatcher->parse(
new Message(
['Content-Type' => $request->headers->get('Content-Type')],
$request->getContent()
)
);

try {
$fieldDefinitions = $this->fieldsByExpressionService->getFieldsFromExpression(
$input->expression,
$input->configuration,
);
} catch (FieldTypeExpressionParserException $e) {
throw new BadRequestException($e->getMessage(), $e->getCode(), $e);
}

return new FieldDefinitionInfoList($fieldDefinitions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\AdminUi\DependencyInjection\Configuration\Parser;

use Ibexa\Bundle\Core\DependencyInjection\Configuration\AbstractParser;
use Ibexa\Bundle\Core\DependencyInjection\Configuration\SiteAccessAware\ContextualizerInterface;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;

/**
* Configuration parser for mapping content type fields expressions.
*
* Example configuration:
*
* ```yaml
* ibexa:
* system:
* default:
* content_type_field_type_groups:
* configurations:
* vectorizable_fields: [ezstring, eztext]
* ```
*/
final class ContentTypeFieldsByExpression extends AbstractParser
{
public function addSemanticConfig(NodeBuilder $nodeBuilder): void
{
$nodeBuilder
->arrayNode('content_type_field_type_groups')
->addDefaultsIfNotSet()
->children()
->arrayNode('configurations')
->useAttributeAsKey('name')
->arrayPrototype()
->scalarPrototype()->end()
->end()
->defaultValue([])
->end()
->end()
->end();
}

/**
* @param array<string,mixed> $scopeSettings
*/
public function mapConfig(array &$scopeSettings, $currentScope, ContextualizerInterface $contextualizer): void
{
if (!isset($scopeSettings['content_type_field_type_groups'])) {
return;
}

$configurations = $scopeSettings['content_type_field_type_groups']['configurations'] ?? [];
foreach ($configurations as $name => $config) {
$contextualizer->setContextualParameter(
"content_type_field_type_groups.configurations.$name",
$currentScope,
$config
);
}
}
}
1 change: 1 addition & 0 deletions src/bundle/IbexaAdminUiBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private function getConfigParsers(): array
new Parser\AdminUiForms(),
new Parser\ContentType(),
new Parser\ContentTypeGroup(),
new Parser\ContentTypeFieldsByExpression(),
new Parser\SubtreePath(),
new Parser\LimitationValueTemplates(),
new Parser\Assets(),
Expand Down
11 changes: 11 additions & 0 deletions src/bundle/Resources/config/routing_rest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,14 @@ ibexa.rest.image.download:
methods: GET
requirements:
contentIdList: '^\d+(,\d+)*$'

#
# Content type fields by expression
#

ibexa.rest.content_type.load_field_definitions_from_expression:
path: /content-type/load-field-definitions-from-expression
controller: 'Ibexa\Bundle\AdminUi\Controller\ContentTypeFieldsByExpressionController::loadFieldDefinitionsFromExpression'
methods: [POST]
options:
expose: true
7 changes: 7 additions & 0 deletions src/bundle/Resources/config/services/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,10 @@ services:
$imageMappings: '%ibexa.dam_widget.image.mappings%'
tags:
- controller.service_arguments

Ibexa\Bundle\AdminUi\Controller\ContentTypeFieldsByExpressionController:
parent: Ibexa\Rest\Server\Controller
arguments:
$fieldsByExpressionService: '@Ibexa\Contracts\AdminUi\ContentType\ContentTypeFieldsByExpressionServiceInterface'
tags:
- controller.service_arguments
12 changes: 12 additions & 0 deletions src/bundle/Resources/config/services/rest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,15 @@ services:
Ibexa\AdminUi\REST\Input\Parser\CriterionProcessor:
parent: Ibexa\Contracts\Rest\Input\Parser\Query\Criterion\BaseCriterionProcessor

#
# Content type
#
Ibexa\AdminUi\REST\Input\Parser\ContentType\FieldDefinitionExpression:
parent: Ibexa\Rest\Server\Common\Parser
tags:
- { name: ibexa.rest.input.parser, mediaType: application/vnd.ibexa.api.FieldDefinitionExpression }

Ibexa\AdminUi\REST\Output\ValueObjectVisitor\ContentType\FieldDefinitionInfoList:
parent: Ibexa\Contracts\Rest\Output\ValueObjectVisitor
tags:
- { name: ibexa.rest.output.value_object.visitor, type: Ibexa\AdminUi\REST\Value\ContentType\FieldDefinitionInfoList }
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ interface ContentTypeFieldsByExpressionServiceInterface
* @return list<\Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition>
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\AdminUi\Exception\FieldTypeExpressionParserException
* @throws \LogicException
*/
public function getFieldsFromExpression(string $expression): array;
public function getFieldsFromExpression(string $expression, ?string $configuration = null): array;

/**
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
Expand Down
32 changes: 29 additions & 3 deletions src/lib/ContentType/ContentTypeFieldsByExpressionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@

use Ibexa\AdminUi\Util\ContentTypeFieldsExtractorInterface;
use Ibexa\Contracts\AdminUi\ContentType\ContentTypeFieldsByExpressionServiceInterface;
use Ibexa\Contracts\Core\Persistence\Content\Language\Handler as ContentLanguageHandler;
use Ibexa\Contracts\Core\Persistence\Content\Type\Handler as ContentTypeHandler;
use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Core\FieldType\FieldTypeRegistry;
use Ibexa\Core\Repository\Mapper\ContentTypeDomainMapper;

final class ContentTypeFieldsByExpressionService implements ContentTypeFieldsByExpressionServiceInterface
Expand All @@ -23,26 +26,49 @@ final class ContentTypeFieldsByExpressionService implements ContentTypeFieldsByE

private ContentTypeDomainMapper $contentTypeDomainMapper;

private ConfigResolverInterface $configResolver;

public function __construct(
ContentTypeFieldsExtractorInterface $fieldsExtractor,
ContentTypeHandler $contentTypeHandler,
ContentTypeDomainMapper $contentTypeDomainMapper
ContentLanguageHandler $contentLanguageHandler,
FieldTypeRegistry $fieldTypeRegistry,
ConfigResolverInterface $configResolver
) {
$this->fieldsExtractor = $fieldsExtractor;
$this->contentTypeHandler = $contentTypeHandler;
$this->contentTypeDomainMapper = $contentTypeDomainMapper;
// Building ContentTypeDomainMapper manually to avoid circular dependency.
//TODO handle after core merge
$this->contentTypeDomainMapper = new ContentTypeDomainMapper(
$contentTypeHandler,
$contentLanguageHandler,
$fieldTypeRegistry,
);
$this->configResolver = $configResolver;
}

public function getFieldsFromExpression(string $expression): array
public function getFieldsFromExpression(string $expression, ?string $configuration = null): array
{
$contentTypeFieldIds = $this->fieldsExtractor->extractFieldsFromExpression($expression);

$configuration = $configuration !== null
? $this->configResolver->getParameter("content_type_field_type_groups.configurations.$configuration")
: null;

$contentTypeFieldDefinitions = [];
foreach ($contentTypeFieldIds as $contentTypeFieldId) {
$persistenceFieldDefinition = $this->contentTypeHandler->getFieldDefinition(
$contentTypeFieldId,
ContentType::STATUS_DEFINED,
);

if (
$configuration !== null
&& !in_array($persistenceFieldDefinition->fieldType, $configuration, true)
) {
continue;
}

$apiFieldDefinition = $this->contentTypeDomainMapper->buildFieldDefinitionDomainObject(
$persistenceFieldDefinition,
$persistenceFieldDefinition->mainLanguageCode,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\AdminUi\REST\Input\Parser\ContentType;

use Ibexa\AdminUi\REST\Value\ContentType\FieldDefinitionExpression as FieldDefinitionExpressionValue;
use Ibexa\Contracts\Rest\Exceptions;
use Ibexa\Contracts\Rest\Input\ParsingDispatcher;
use Ibexa\Rest\Input\BaseParser;

final class FieldDefinitionExpression extends BaseParser
{
public function parse(array $data, ParsingDispatcher $parsingDispatcher): FieldDefinitionExpressionValue
{
if (!array_key_exists('expression', $data) || !is_string($data['expression'])) {
throw new Exceptions\Parser(
sprintf("Missing or invalid 'expression' property for %s.", FieldDefinitionExpressionValue::class)
);
}

return new FieldDefinitionExpressionValue($data['expression'], $data['configuration'] ?? null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\AdminUi\REST\Output\ValueObjectVisitor\ContentType;

use Ibexa\Contracts\Rest\Output\Generator;
use Ibexa\Contracts\Rest\Output\Visitor;
use Ibexa\Rest\Server\Output\ValueObjectVisitor\RestContentTypeBase;

final class FieldDefinitionInfoList extends RestContentTypeBase
{
/**
* @param \Ibexa\AdminUi\REST\Value\ContentType\FieldDefinitionInfoList $data
*/
public function visit(Visitor $visitor, Generator $generator, $data): void
{
$fieldDefinitionList = $data;

$generator->startObjectElement('FieldDefinitions', 'FieldDefinitionInfoList');
$visitor->setHeader('Content-Type', $generator->getMediaType('FieldDefinitionInfoList'));

$generator->startList('FieldDefinitionInfo');
foreach ($fieldDefinitionList->fieldDefinitions as $fieldDefinition) {
$generator->startObjectElement('FieldDefinitionInfo');

$generator->valueElement('id', $fieldDefinition->id);
$generator->valueElement('identifier', $fieldDefinition->identifier);
$generator->valueElement('position', $fieldDefinition->position);

$this->visitNamesList($generator, $fieldDefinition->getNames());

$generator->endObjectElement('FieldDefinitionInfo');
}
$generator->endList('FieldDefinitionInfo');

$generator->endObjectElement('FieldDefinitions');
}
}
24 changes: 24 additions & 0 deletions src/lib/REST/Value/ContentType/FieldDefinitionExpression.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\AdminUi\REST\Value\ContentType;

use Ibexa\Rest\Value as RestValue;

final class FieldDefinitionExpression extends RestValue
{
public string $expression;

public ?string $configuration = null;

public function __construct(string $expression, ?string $configuration = null)
{
$this->expression = $expression;
$this->configuration = $configuration;
}
}
25 changes: 25 additions & 0 deletions src/lib/REST/Value/ContentType/FieldDefinitionInfoList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\AdminUi\REST\Value\ContentType;

use Ibexa\Rest\Value as RestValue;

final class FieldDefinitionInfoList extends RestValue
{
/** @var \Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition[] */
public array $fieldDefinitions;

/**
* @param \Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition[] $fieldDefinitions
*/
public function __construct(array $fieldDefinitions)
{
$this->fieldDefinitions = $fieldDefinitions;
}
}
2 changes: 2 additions & 0 deletions src/lib/Util/ContentTypeFieldsExtractorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ interface ContentTypeFieldsExtractorInterface
* @return list<int>
*
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
* @throws \Ibexa\AdminUi\Exception\FieldTypeExpressionParserException
* @throws \LogicException
Copy link
Contributor

Choose a reason for hiding this comment

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

This cannot be declared for the interface. It has to be a different type of exception, if needed.

Suggested change
* @throws \LogicException

*/
public function extractFieldsFromExpression(string $expression): array;

Expand Down
Loading
Loading