Skip to content
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
20 changes: 17 additions & 3 deletions packages/guides-cli/resources/schema/guides.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,27 @@

<xsd:complexType name="sanitizer">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="allow-element" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="allow-element" type="element-option" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="block-element" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="drop-element" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="allow-attribute" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="drop-attribute" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="allow-attribute" type="attribute-option" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="drop-attribute" type="attribute-option" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>

<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>

<xsd:complexType name="element-option">
<xsd:sequence>
<xsd:element name="attribute" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>

<xsd:complexType name="attribute-option">
<xsd:sequence>
<xsd:element name="element" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:schema>
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,16 @@

->load(
'phpDocumentor\\Guides\RestructuredText\\Parser\\Productions\\InlineRules\\',
'%vendor_dir%/phpdocumentor/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules',
'../../src/RestructuredText/Parser/Productions/InlineRules',
)
->load(
'phpDocumentor\\Guides\RestructuredText\\NodeRenderers\\Html\\',
'%vendor_dir%/phpdocumentor/guides-restructured-text/src/RestructuredText/NodeRenderers/Html',
'../../src/RestructuredText/NodeRenderers/Html',
)
->tag('phpdoc.guides.noderenderer.html')
->load(
'phpDocumentor\\Guides\RestructuredText\\NodeRenderers\\LaTeX\\',
'%vendor_dir%/phpdocumentor/guides-restructured-text/src/RestructuredText/NodeRenderers/LaTeX',
'../../src/RestructuredText/NodeRenderers/LaTeX',
)
->tag('phpdoc.guides.noderenderer.tex')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/*
->load(
'phpDocumentor\\Guides\RstTheme\\NodeRenderers\\Rst\\',
'%vendor_dir%/phpdocumentor/guides-rst-theme/src/RstTheme/NodeRenderers/Rst',
'../../src/RstTheme/NodeRenderers/Rst',
)
->tag('phpdoc.guides.noderenderer.rst')
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/guides/resources/config/guides.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,16 @@

->load(
'phpDocumentor\\Guides\\Compiler\\NodeTransformers\\',
'%vendor_dir%/phpdocumentor/guides/src/Compiler/NodeTransformers/*Transformer.php',
'../../src/Compiler/NodeTransformers/*Transformer.php',
)
->load(
'phpDocumentor\\Guides\\Compiler\\NodeTransformers\\MenuNodeTransformers\\',
'%vendor_dir%/phpdocumentor/guides/src/Compiler/NodeTransformers/MenuNodeTransformers/*Transformer.php',
'../../src/Compiler/NodeTransformers/MenuNodeTransformers/*Transformer.php',
)

->load(
'phpDocumentor\\Guides\\Compiler\\Passes\\',
'%vendor_dir%/phpdocumentor/guides/src/Compiler/Passes/*Pass.php',
'../../src/Compiler/Passes/*Pass.php',
)

->set(InternalMenuEntryNodeTransformer::class)
Expand Down
50 changes: 42 additions & 8 deletions packages/guides/src/DependencyInjection/GuidesExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,21 +183,55 @@ static function ($value) {
->scalarNode('sanitizer_name')->end()
->arrayNode('sanitizers')
->defaultValue([])
->useAttributeAsKey('name')
->arrayPrototype()
->fixXmlConfig('allow_element')
->fixXmlConfig('drop_element')
->fixXmlConfig('block_element')
->fixXmlConfig('allow_attribute')
->fixXmlConfig('drop_attribute')
->children()
->scalarNode('name')->isRequired()->end()
->booleanNode('allow_safe_elements')->defaultValue(true)->end()
->booleanNode('allow_static_elements')->defaultValue(true)->end()
->arrayNode('allow_elements')->scalarPrototype()->end()->end()
->arrayNode('block_elements')->scalarPrototype()->end()->end()
->arrayNode('drop_elements')->scalarPrototype()->end()->end()
->arrayNode('allow_attributes')->scalarPrototype()->end()->end()
->arrayNode('drop_attributes')->scalarPrototype()->end()->end()
->arrayNode('allow_elements')
->normalizeKeys(false)
->useAttributeAsKey('name')
->variablePrototype()
->beforeNormalization()
->ifArray()->then(static fn ($n) => $n['attribute'] ?? $n)
->end()
->validate()
->ifTrue(static fn ($n): bool => !is_string($n) && !is_array($n))
->thenInvalid('The value must be either a string or an array of strings.')
->end()
->end()
->end()
->arrayNode('block_elements')
->beforeNormalization()->castToArray()->end()
->scalarPrototype()->end()
->end()
->arrayNode('drop_elements')
->beforeNormalization()->castToArray()->end()
->scalarPrototype()->end()
->end()
->arrayNode('allow_attributes')
->normalizeKeys(false)
->useAttributeAsKey('name')
->variablePrototype()
->beforeNormalization()
->ifArray()->then(static fn ($n) => $n['element'] ?? $n)
->end()
->end()
->end()
->arrayNode('drop_attributes')
->normalizeKeys(false)
->useAttributeAsKey('name')
->variablePrototype()
->beforeNormalization()
->ifArray()->then(static fn ($n) => $n['element'] ?? $n)
->end()
->end()
->end()
->end()
->end()
->end()
Expand Down Expand Up @@ -413,8 +447,8 @@ private function configureSanitizers(array $rawNodeConfig, ContainerBuilder $con
return;
}

foreach ($rawNodeConfig['sanitizers'] as $sanitizerConfig) {
$def = $container->register('phpdoc.guides.raw_node.sanitizer.' . $sanitizerConfig['name'], HtmlSanitizerConfig::class);
foreach ($rawNodeConfig['sanitizers'] as $sanitizerName => $sanitizerConfig) {
$def = $container->register('phpdoc.guides.raw_node.sanitizer.' . $sanitizerName, HtmlSanitizerConfig::class);

// Base
if ($sanitizerConfig['allow_safe_elements']) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\DependencyInjection;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;

use function array_filter;
use function array_values;

class GuidesExtensionTest extends TestCase
{
/**
* @param array<array<mixed>> $configs
* @param callable(ContainerBuilder):void $assertions
*/
#[DataProvider('provideConfigs')]
public function testLoad(array $configs, callable $assertions): void
{
$container = new ContainerBuilder();

$extension = new GuidesExtension();
$extension->load($configs, $container);

$assertions($container);
}

/** @return iterable<string, array{array<mixed>, callable(ContainerBuilder):void}> */
public static function provideConfigs(): iterable
{
$sanitizerAssertions = static function (ContainerBuilder $container): void {
self::assertTrue($container->hasDefinition('phpdoc.guides.raw_node.sanitizer.default'));

$definition = $container->getDefinition('phpdoc.guides.raw_node.sanitizer.default');
$allowElementMethodCalls = array_values(array_filter($definition->getMethodCalls(), static fn (array $call) => $call[0] === 'allowElement'));
self::assertCount(1, $allowElementMethodCalls);
self::assertSame(['object', ['type', 'data', 'alt']], $allowElementMethodCalls[0][1]);
};

yield 'sanitizer' => [
[
[
'raw_node' => [
'sanitizers' => [
'default' => [
'allow_elements' => [
'object' => ['type', 'data', 'alt'],
],
],
],
],
],
],
$sanitizerAssertions,
];

yield 'sanitizer XML' => [
[
[
'raw_node' => [
'sanitizer' => [
'name' => 'default',
'allow_element' => [
[
'name' => 'object',
'attribute' => ['type', 'data', 'alt'],
],
],
],
],
],
],
$sanitizerAssertions,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<project title="Project Title" version="6.4"/>
<raw-node sanitizer-name="custom" >
<sanitizer name="custom">
<allow-element>p</allow-element>
<allow-element name="p"/>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both the old and new config work, but it's not (nicely) possible to combine simple type (string content) and complex type (attributes/child elements) in XSD. The schema has been updated to a complex type, to allow specifying the allowed attributes, which means this file had to be updated to conform to the new schema.

<block-element>div</block-element>
<drop-element>h2</drop-element>
</sanitizer>
Expand Down
Loading