Skip to content

Commit b254b91

Browse files
committed
IBX-10262: Renamed and refactored CustomTagsValidator to support both Custom Tags and Styles
1 parent 12090a8 commit b254b91

File tree

6 files changed

+195
-181
lines changed

6 files changed

+195
-181
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,30 +1260,6 @@ parameters:
12601260
count: 1
12611261
path: src/lib/RichText/TextExtractor/ShortTextExtractor.php
12621262

1263-
-
1264-
message: '#^Argument of an invalid type DOMNodeList\<DOMNode\>\|false supplied for foreach, only iterables are supported\.$#'
1265-
identifier: foreach.nonIterable
1266-
count: 2
1267-
path: src/lib/RichText/Validator/CustomTagsValidator.php
1268-
1269-
-
1270-
message: '#^Call to an undefined method DOMNode\:\:getAttribute\(\)\.$#'
1271-
identifier: method.notFound
1272-
count: 2
1273-
path: src/lib/RichText/Validator/CustomTagsValidator.php
1274-
1275-
-
1276-
message: '#^Method Ibexa\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidator\:\:__construct\(\) has parameter \$customTagsConfiguration with no value type specified in iterable type array\.$#'
1277-
identifier: missingType.iterableValue
1278-
count: 1
1279-
path: src/lib/RichText/Validator/CustomTagsValidator.php
1280-
1281-
-
1282-
message: '#^Property Ibexa\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidator\:\:\$customTagsConfiguration type has no value type specified in iterable type array\.$#'
1283-
identifier: missingType.iterableValue
1284-
count: 1
1285-
path: src/lib/RichText/Validator/CustomTagsValidator.php
1286-
12871263
-
12881264
message: '#^Argument of an invalid type DOMNodeList\<DOMNode\>\|false supplied for foreach, only iterables are supported\.$#'
12891265
identifier: foreach.nonIterable
@@ -3480,30 +3456,6 @@ parameters:
34803456
count: 6
34813457
path: tests/lib/RichText/RendererTest.php
34823458

3483-
-
3484-
message: '#^Method Ibexa\\Tests\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidatorTest\:\:providerForTestValidateDocument\(\) return type has no value type specified in iterable type array\.$#'
3485-
identifier: missingType.iterableValue
3486-
count: 1
3487-
path: tests/lib/RichText/Validator/CustomTagsValidatorTest.php
3488-
3489-
-
3490-
message: '#^Method Ibexa\\Tests\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidatorTest\:\:testValidateDocument\(\) has no return type specified\.$#'
3491-
identifier: missingType.return
3492-
count: 1
3493-
path: tests/lib/RichText/Validator/CustomTagsValidatorTest.php
3494-
3495-
-
3496-
message: '#^Method Ibexa\\Tests\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidatorTest\:\:testValidateDocument\(\) has parameter \$expectedErrors with no value type specified in iterable type array\.$#'
3497-
identifier: missingType.iterableValue
3498-
count: 1
3499-
path: tests/lib/RichText/Validator/CustomTagsValidatorTest.php
3500-
3501-
-
3502-
message: '#^Method Ibexa\\Tests\\FieldTypeRichText\\RichText\\Validator\\CustomTagsValidatorTest\:\:testValidateDocumentAcceptsLegacyTags\(\) has no return type specified\.$#'
3503-
identifier: missingType.return
3504-
count: 1
3505-
path: tests/lib/RichText/Validator/CustomTagsValidatorTest.php
3506-
35073459
-
35083460
message: '#^Call to method validateDocument\(\) on an unknown class Ibexa\\FieldTypeRichText\\RichText\\ValidatorInterface\.$#'
35093461
identifier: class.notFound

src/bundle/Resources/config/settings/fieldtype_services.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ services:
4141
class: Ibexa\FieldTypeRichText\RichText\Normalizer\Aggregate
4242

4343
# Symfony 3.4+ service definitions:
44-
Ibexa\FieldTypeRichText\RichText\Validator\CustomTagsValidator:
44+
Ibexa\FieldTypeRichText\RichText\Validator\CustomTemplateValidator:
4545
public: false
46-
arguments: ['%ibexa.field_type.richtext.custom_tags%']
46+
arguments:
47+
$customTagsConfiguration: '%ibexa.field_type.richtext.custom_tags%'
48+
$customStylesConfiguration: '%ibexa.field_type.richtext.custom_styles%'
4749
tags:
4850
- { name: ibexa.field_type.richtext.validator.input.xhtml5 }
4951

src/lib/RichText/Validator/CustomTagsValidator.php

Lines changed: 0 additions & 105 deletions
This file was deleted.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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\FieldTypeRichText\RichText\Validator;
10+
11+
use DOMDocument;
12+
use DOMElement;
13+
use DOMNodeList;
14+
use DOMXPath;
15+
use Ibexa\Contracts\FieldTypeRichText\RichText\ValidatorInterface;
16+
17+
/**
18+
* Validator for Custom Tags and Styles input.
19+
*
20+
* The Validator checks if the given XML reflects proper Custom Tags or Styles configuration,
21+
* mostly the existence of a specific Custom Tag or Style and their required attributes.
22+
*/
23+
class CustomTemplateValidator implements ValidatorInterface
24+
{
25+
/**
26+
* Custom Tags global configuration (ibexa.richtext.custom_tags Semantic Config).
27+
*
28+
* @var array<string,array{template:string, is_inline:bool, icon:string, attributes:array<string, array{type: string, required: bool, default_value: mixed}>}>
29+
*/
30+
private array $customTagsConfiguration;
31+
32+
/**
33+
* Custom Styles global configuration (ibexa.richtext.custom_styles Semantic Config).
34+
*
35+
* @var array<string,array{template:string,inline:bool}>
36+
*/
37+
private array $customStylesConfiguration;
38+
39+
/**
40+
* CustomTemplateValidator constructor.
41+
*
42+
* @param array<string,array{template:string, is_inline:bool, icon:string, attributes:array<string, array{type: string, required: bool, default_value: mixed}>}> $customTagsConfiguration
43+
* @param array<string,array{template:string, inline:bool}> $customStylesConfiguration
44+
*/
45+
public function __construct(
46+
array $customTagsConfiguration,
47+
array $customStylesConfiguration
48+
) {
49+
$this->customTagsConfiguration = $customTagsConfiguration;
50+
$this->customStylesConfiguration = $customStylesConfiguration;
51+
}
52+
53+
/**
54+
* Validate Custom Tags found in the document.
55+
*
56+
* @return string[] an array of error messages
57+
*/
58+
public function validateDocument(DOMDocument $xmlDocument): array
59+
{
60+
$configuredTemplateNames = array_merge(array_keys($this->customTagsConfiguration), array_keys($this->customStylesConfiguration));
61+
$errors = [];
62+
63+
$xpath = new DOMXPath($xmlDocument);
64+
$xpath->registerNamespace('docbook', 'http://docbook.org/ns/docbook');
65+
66+
$eztemplateElements = $xpath->query('//docbook:eztemplate');
67+
if ($eztemplateElements instanceof DOMNodeList) {
68+
foreach ($eztemplateElements as $tagElement) {
69+
if (!$tagElement instanceof DOMElement) {
70+
continue;
71+
}
72+
$tagName = $tagElement->getAttribute('name');
73+
if (empty($tagName)) {
74+
$errors[] = 'Missing RichText Custom Tag name';
75+
continue;
76+
}
77+
78+
if (!in_array($tagName, $configuredTemplateNames, true)) {
79+
@trigger_error(
80+
"Configuration for RichText Custom Tag or Custom Style '{$tagName}' not found. " .
81+
'Custom Tags and Custom Style configuration is required since 7.1, its lack will result in validation error in 8.x',
82+
E_USER_DEPRECATED
83+
);
84+
continue;
85+
}
86+
87+
// Custom Styles does not have any attributes, so we can skip validation for them
88+
if (isset($this->customStylesConfiguration[$tagName])) {
89+
continue;
90+
}
91+
92+
$nonEmptyAttributes = [];
93+
$tagAttributes = $this->customTagsConfiguration[$tagName]['attributes'];
94+
95+
// iterate over all attributes defined in XML document to check if their names match configuration
96+
$configElements = $xpath->query('./docbook:ezconfig/docbook:ezvalue', $tagElement);
97+
if ($configElements instanceof DOMNodeList) {
98+
foreach ($configElements as $configElement) {
99+
if (!$configElement instanceof DOMElement) {
100+
continue;
101+
}
102+
$attributeName = $configElement->getAttribute('key');
103+
if (empty($attributeName)) {
104+
$errors[] = "Missing attribute name for RichText Custom Tag '{$tagName}'";
105+
continue;
106+
}
107+
if (!isset($tagAttributes[$attributeName])) {
108+
$errors[] = "Unknown attribute '{$attributeName}' of RichText Custom Tag '{$tagName}'";
109+
}
110+
111+
// collect information about non-empty attributes
112+
if (!empty($configElement->textContent)) {
113+
$nonEmptyAttributes[] = $attributeName;
114+
}
115+
}
116+
}
117+
118+
// check if all required attributes are present
119+
foreach ($tagAttributes as $attributeName => $attributeSettings) {
120+
if (empty($attributeSettings['required'])) {
121+
continue;
122+
}
123+
124+
if (!in_array($attributeName, $nonEmptyAttributes)) {
125+
$errors[] = "The attribute '{$attributeName}' of RichText Custom Tag '{$tagName}' cannot be empty";
126+
}
127+
}
128+
}
129+
}
130+
131+
return $errors;
132+
}
133+
}
134+
135+
class_alias(CustomTemplateValidator::class, 'EzSystems\EzPlatformRichText\eZ\RichText\Validator\CustomTagsValidator');

0 commit comments

Comments
 (0)