Skip to content

Commit 0da192d

Browse files
committed
IBX-9631: Added method validating if field def id is within an expression
1 parent 31dda07 commit 0da192d

File tree

8 files changed

+230
-0
lines changed

8 files changed

+230
-0
lines changed

src/bundle/Resources/config/services/services.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ services:
88

99
Ibexa\AdminUi\Service\MetaFieldType\MetaFieldDefinitionServiceInterface:
1010
'@Ibexa\AdminUi\Service\MetaFieldType\MetaFieldDefinitionService'
11+
12+
Ibexa\AdminUi\Service\ContentTypeFieldsByExpressionService: ~
13+
14+
Ibexa\Contracts\AdminUi\Service\ContentTypeFieldsByExpressionServiceInterface:
15+
'@Ibexa\AdminUi\Service\ContentTypeFieldsByExpressionService'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Contracts\AdminUi\Service;
10+
11+
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
12+
13+
interface ContentTypeFieldsByExpressionServiceInterface
14+
{
15+
/**
16+
* @return list<\Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition>
17+
*
18+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
19+
*/
20+
public function getFieldsFromExpression(string $expression): array;
21+
22+
/**
23+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
24+
*/
25+
public function isFieldIncludedInExpression(FieldDefinition $fieldDefinition, string $expression): bool;
26+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\AdminUi\Service;
10+
11+
use Ibexa\AdminUi\Util\ContentTypeFieldsExtractorInterface;
12+
use Ibexa\Contracts\AdminUi\Service\ContentTypeFieldsByExpressionServiceInterface;
13+
use Ibexa\Contracts\Core\Persistence\Content\Type\Handler as ContentTypeHandler;
14+
use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentType;
15+
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
16+
use Ibexa\Core\Repository\Mapper\ContentTypeDomainMapper;
17+
18+
final class ContentTypeFieldsByExpressionService implements ContentTypeFieldsByExpressionServiceInterface
19+
{
20+
private ContentTypeFieldsExtractorInterface $fieldsExtractor;
21+
22+
private ContentTypeHandler $contentTypeHandler;
23+
24+
private ContentTypeDomainMapper $contentTypeDomainMapper;
25+
26+
public function __construct(
27+
ContentTypeFieldsExtractorInterface $fieldsExtractor,
28+
ContentTypeHandler $contentTypeHandler,
29+
ContentTypeDomainMapper $contentTypeDomainMapper
30+
) {
31+
$this->fieldsExtractor = $fieldsExtractor;
32+
$this->contentTypeHandler = $contentTypeHandler;
33+
$this->contentTypeDomainMapper = $contentTypeDomainMapper;
34+
}
35+
36+
public function getFieldsFromExpression(string $expression): array
37+
{
38+
$contentTypeFieldIds = $this->fieldsExtractor->extractFieldsFromExpression($expression);
39+
40+
$contentTypeFieldDefinitions = [];
41+
foreach ($contentTypeFieldIds as $contentTypeFieldId) {
42+
$persistenceFieldDefinition = $this->contentTypeHandler->getFieldDefinition(
43+
$contentTypeFieldId,
44+
ContentType::STATUS_DEFINED,
45+
);
46+
$apiFieldDefinition = $this->contentTypeDomainMapper->buildFieldDefinitionDomainObject(
47+
$persistenceFieldDefinition,
48+
$persistenceFieldDefinition->mainLanguageCode,
49+
);
50+
51+
$contentTypeFieldDefinitions[] = $apiFieldDefinition;
52+
}
53+
54+
return $contentTypeFieldDefinitions;
55+
}
56+
57+
public function isFieldIncludedInExpression(FieldDefinition $fieldDefinition, string $expression): bool
58+
{
59+
return $this->fieldsExtractor->isFieldWithinExpression($fieldDefinition->getId(), $expression);
60+
}
61+
}

src/lib/Util/ContentTypeFieldsExtractor.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ public function extractFieldsFromExpression(string $expression): array
3737
return $this->mergeFieldIds($extractedMetadata[2], $contentTypes);
3838
}
3939

40+
public function isFieldWithinExpression(int $fieldDefinitionId, string $expression): bool
41+
{
42+
$fieldsFromExpression = $this->extractFieldsFromExpression($expression);
43+
44+
return in_array($fieldDefinitionId, $fieldsFromExpression, true);
45+
}
46+
4047
/**
4148
* @param array{non-empty-list<string>|null, non-empty-list<string>|null, non-empty-list<string>|null} $extractedMetadata
4249
*

src/lib/Util/ContentTypeFieldsExtractorInterface.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ interface ContentTypeFieldsExtractorInterface
1616
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
1717
*/
1818
public function extractFieldsFromExpression(string $expression): array;
19+
20+
/**
21+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException
22+
*/
23+
public function isFieldWithinExpression(int $fieldDefinitionId, string $expression): bool;
1924
}

tests/integration/AdminUiIbexaTestKernel.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Ibexa\Bundle\Search\IbexaSearchBundle;
2020
use Ibexa\Bundle\Test\Rest\IbexaTestRestBundle;
2121
use Ibexa\Bundle\User\IbexaUserBundle;
22+
use Ibexa\Contracts\AdminUi\Service\ContentTypeFieldsByExpressionServiceInterface;
2223
use Ibexa\Contracts\Core\Persistence\Content\Type\Handler as ContentTypeHandler;
2324
use Ibexa\Contracts\Core\Repository\BookmarkService;
2425
use Ibexa\Contracts\Test\Core\IbexaTestKernel;
@@ -67,6 +68,8 @@ protected static function getExposedServicesByClass(): iterable
6768
yield ContentTypeFieldsExtractorInterface::class;
6869

6970
yield ContentTypeHandler::class;
71+
72+
yield ContentTypeFieldsByExpressionServiceInterface::class;
7073
}
7174

7275
protected static function getExposedServicesById(): iterable
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Tests\Integration\AdminUi\Service;
10+
11+
use Ibexa\Contracts\AdminUi\Service\ContentTypeFieldsByExpressionServiceInterface;
12+
use Ibexa\Contracts\Core\Repository\ContentTypeService;
13+
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
14+
use Ibexa\Contracts\Core\Test\IbexaKernelTestCase;
15+
16+
final class ContentTypeFieldsByExpressionServiceTest extends IbexaKernelTestCase
17+
{
18+
private ContentTypeFieldsByExpressionServiceInterface $fieldsFromExpressionService;
19+
20+
private ContentTypeService $contentTypeService;
21+
22+
protected function setUp(): void
23+
{
24+
self::bootKernel();
25+
self::setAdministratorUser();
26+
27+
$this->fieldsFromExpressionService = self::getServiceByClassName(ContentTypeFieldsByExpressionServiceInterface::class);
28+
$this->contentTypeService = self::getServiceByClassName(ContentTypeService::class);
29+
}
30+
31+
public function testExtractWithContentTypeGroupNames(): void
32+
{
33+
$expression = '{Content}/folder/name';
34+
35+
$extractedFieldDefinitions = $this->fieldsFromExpressionService->getFieldsFromExpression($expression);
36+
37+
self::assertCount(1, $extractedFieldDefinitions);
38+
$fieldDefinition = $extractedFieldDefinitions[0];
39+
self::assertSame('name', $fieldDefinition->identifier);
40+
self::assertSame('ezstring', $fieldDefinition->fieldTypeIdentifier);
41+
}
42+
43+
public function testFieldIdWithinExpression(): void
44+
{
45+
$expression = '{Content}/folder/name';
46+
47+
$contentType = $this->contentTypeService->loadContentTypeByIdentifier('folder');
48+
$fieldDefinitions = $contentType->getFieldDefinitions();
49+
$nameFieldDefinition = $fieldDefinitions->filter(
50+
static fn (FieldDefinition $fieldDefinition): bool => $fieldDefinition->getIdentifier() === 'name'
51+
)->first();
52+
53+
$result = $this->fieldsFromExpressionService->isFieldIncludedInExpression(
54+
$nameFieldDefinition,
55+
$expression,
56+
);
57+
58+
self::assertTrue($result);
59+
}
60+
}

tests/integration/Util/ContentTypeFieldsExtractorTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
use Ibexa\AdminUi\Util\ContentTypeFieldsExtractorInterface;
1212
use Ibexa\Contracts\Core\Persistence\Content\Type\Handler as ContentTypeHandler;
13+
use Ibexa\Contracts\Core\Repository\ContentTypeService;
14+
use Ibexa\Contracts\Core\Repository\Values\ContentType\FieldDefinition;
1315
use Ibexa\Contracts\Core\Test\IbexaKernelTestCase;
1416
use LogicException;
1517

@@ -19,13 +21,16 @@ final class ContentTypeFieldsExtractorTest extends IbexaKernelTestCase
1921

2022
private ContentTypeHandler $contentTypeHandler;
2123

24+
private ContentTypeService $contentTypeService;
25+
2226
protected function setUp(): void
2327
{
2428
self::bootKernel();
2529
self::setAdministratorUser();
2630

2731
$this->contentTypeFieldsExtractor = self::getServiceByClassName(ContentTypeFieldsExtractorInterface::class);
2832
$this->contentTypeHandler = self::getServiceByClassName(ContentTypeHandler::class);
33+
$this->contentTypeService = self::getServiceByClassName(ContentTypeService::class);
2934
}
3035

3136
public function testExtractWithContentTypeGroupNames(): void
@@ -75,4 +80,62 @@ public function testExtractWithContentTypeAndGroupNamesFailsWithTypesOutsideGrou
7580

7681
$this->contentTypeFieldsExtractor->extractFieldsFromExpression($expression);
7782
}
83+
84+
/**
85+
* @dataProvider dataProviderForTestFieldIdWithinExpression
86+
*/
87+
public function testFieldIdWithinExpression(string $expression): void
88+
{
89+
$contentType = $this->contentTypeService->loadContentTypeByIdentifier('folder');
90+
$fieldDefinitions = $contentType->getFieldDefinitions();
91+
$nameFieldDefinition = $fieldDefinitions->filter(
92+
static fn (FieldDefinition $fieldDefinition): bool => $fieldDefinition->getIdentifier() === 'name'
93+
)->first();
94+
95+
$result = $this->contentTypeFieldsExtractor->isFieldWithinExpression($nameFieldDefinition->getId(), $expression);
96+
97+
self::assertTrue($result);
98+
}
99+
100+
/**
101+
* @dataProvider dataProviderForTestFieldIdNotWithinExpression
102+
*/
103+
public function testFieldIdNotWithinExpression(string $expression): void
104+
{
105+
$contentType = $this->contentTypeService->loadContentTypeByIdentifier('folder');
106+
$fieldDefinitions = $contentType->getFieldDefinitions();
107+
$nameFieldDefinition = $fieldDefinitions->filter(
108+
static fn (FieldDefinition $fieldDefinition): bool => $fieldDefinition->getIdentifier() === 'name'
109+
)->first();
110+
111+
$result = $this->contentTypeFieldsExtractor->isFieldWithinExpression($nameFieldDefinition->getId(), $expression);
112+
113+
self::assertFalse($result);
114+
}
115+
116+
/**
117+
* @return iterable<list<string>>
118+
*/
119+
public function dataProviderForTestFieldIdWithinExpression(): iterable
120+
{
121+
yield '{Media,Content}/*/name' => ['{Media,Content}/*/name'];
122+
123+
yield '*/folder/name' => ['*/folder/name'];
124+
125+
yield '*/*/name' => ['*/*/name'];
126+
127+
yield '*/folder/*' => ['*/folder/*'];
128+
}
129+
130+
/**
131+
* @return iterable<list<string>>
132+
*/
133+
public function dataProviderForTestFieldIdNotWithinExpression(): iterable
134+
{
135+
yield '{Users}/*/name' => ['{Users}/*/name'];
136+
137+
yield '*/article/name' => ['*/article/name'];
138+
139+
yield '*/user/*' => ['*/user/*'];
140+
}
78141
}

0 commit comments

Comments
 (0)