Skip to content

Commit f346063

Browse files
committed
[BUGFIX] Read project version from the DOM so "0.10" is not coerced to 0.1
A <project version="0.10"> in guides.xml was rendered as version 0.1 (title, objects.inv, every |version| substitution). XmlFileLoader parses guides.xml with XmlUtils::convertDomElementToArray(), which runs phpize() on every attribute value, coercing version-like strings into numbers: "0.10" becomes the float 0.1, "1.0" becomes 1, "13.0" becomes 13. Read the <project> attributes (all strings) straight from the DOM, and detach the element before the conversion so phpize never sees them. The version is now read correctly at the source instead of being coerced and patched up afterwards, so the beforeNormalization workaround in the Symfony config is removed. Writing the version directly (version="0.10") now just works. The previous "escaped version" workaround -- version="'3.0'" with single quotes to dodge phpize -- is no longer necessary, but existing guides.xml files may still use it, so the surrounding single quotes are still stripped (for version and release) to keep those files rendering 3.0 rather than the literal '3.0'. A regression fixture covers the quoted form. Reported on docs.typo3.org for netresearch/nr-vault and nr-llm (0.10 / 0.12). Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
1 parent aa8a698 commit f346063

7 files changed

Lines changed: 86 additions & 42 deletions

File tree

packages/guides-cli/src/Config/XmlFileLoader.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace phpDocumentor\Guides\Cli\Config;
1515

16+
use DOMAttr;
17+
use DOMElement;
1618
use Symfony\Component\Config\Loader\FileLoader;
1719
use Symfony\Component\Config\Util\Exception\XmlParsingException;
1820
use Symfony\Component\Config\Util\XmlUtils;
@@ -22,6 +24,7 @@
2224
use function is_array;
2325
use function is_string;
2426
use function sprintf;
27+
use function trim;
2528

2629
final class XmlFileLoader extends FileLoader
2730
{
@@ -36,9 +39,45 @@ public function load(mixed $resource, string|null $type = null): array
3639
throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $resource));
3740
}
3841

42+
// The <project> attributes (title, version, release, copyright) are all
43+
// strings and are read from the DOM directly. XmlUtils::convertDomElementToArray()
44+
// below runs phpize() on every attribute value, which coerces version-like
45+
// strings into numbers ("0.10" would become the float 0.1, "1.0" would
46+
// become 1). Reading them straight from the DOM and detaching <project>
47+
// beforehand keeps the version exactly as written.
48+
$projectConfig = null;
49+
$project = $element->getElementsByTagName('project')->item(0);
50+
if ($project instanceof DOMElement) {
51+
$projectConfig = [];
52+
foreach ($project->attributes as $attribute) {
53+
if (!($attribute instanceof DOMAttr)) {
54+
continue;
55+
}
56+
57+
$value = $attribute->value;
58+
59+
// Backward compatibility: to stop the previous phpize() call from
60+
// turning a version into a number, consumers wrapped it in single
61+
// quotes (e.g. version="'3.0'"). The value is now read straight from
62+
// the DOM so the quotes are no longer needed, but existing guides.xml
63+
// files may still contain them; strip them for these two attributes.
64+
if ($attribute->name === 'version' || $attribute->name === 'release') {
65+
$value = trim($value, "'");
66+
}
67+
68+
$projectConfig[$attribute->name] = $value;
69+
}
70+
71+
$project->parentNode?->removeChild($project);
72+
}
73+
3974
$rootConfig = XmlUtils::convertDomElementToArray($element);
4075
assert(is_array($rootConfig));
4176

77+
if ($projectConfig !== null) {
78+
$rootConfig['project'] = $projectConfig;
79+
}
80+
4281
$configs = [];
4382
if (isset($rootConfig['import'])) {
4483
foreach ((array) $rootConfig['import'] as $import) {

packages/guides/src/DependencyInjection/GuidesExtension.php

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,8 @@
4343
use function assert;
4444
use function dirname;
4545
use function is_array;
46-
use function is_int;
4746
use function is_string;
4847
use function pathinfo;
49-
use function trim;
50-
use function var_export;
5148

5249
final class GuidesExtension extends Extension implements CompilerPassInterface, ConfigurationInterface, PrependExtensionInterface
5350
{
@@ -64,42 +61,8 @@ public function getConfigTreeBuilder(): TreeBuilder
6461
->arrayNode('project')
6562
->children()
6663
->scalarNode('title')->end()
67-
->scalarNode('version')
68-
->beforeNormalization()
69-
->always(
70-
// We need to revert the phpize call in XmlUtils. Version is always a string!
71-
static function ($value) {
72-
if (!is_int($value) && !is_string($value)) {
73-
return var_export($value, true);
74-
}
75-
76-
if (is_string($value)) {
77-
return trim($value, "'");
78-
}
79-
80-
return $value;
81-
},
82-
)
83-
->end()
84-
->end()
85-
->scalarNode('release')
86-
->beforeNormalization()
87-
->always(
88-
// We need to revert the phpize call in XmlUtils. Version is always a string!
89-
static function ($value) {
90-
if (!is_int($value) && !is_string($value)) {
91-
return var_export($value, true);
92-
}
93-
94-
if (is_string($value)) {
95-
return trim($value, "'");
96-
}
97-
98-
return $value;
99-
},
100-
)
101-
->end()
102-
->end()
64+
->scalarNode('version')->end()
65+
->scalarNode('release')->end()
10366
->scalarNode('copyright')->end()
10467
->end()
10568
->end()
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Some Document - Render guides</title>
5+
6+
</head>
7+
<body>
8+
<!-- content start -->
9+
<div class="section" id="some-document">
10+
<h1>Some Document</h1>
11+
12+
<p>Project Render guides in version 3.0, release 3.0.0.</p>
13+
14+
</div>
15+
<!-- content end -->
16+
</body>
17+
</html>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<guides
3+
xmlns="https://www.phpdoc.org/guides"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="https://www.phpdoc.org/guides vendor/phpdocumentor/guides-cli/resources/schema/guides.xsd"
6+
>
7+
<project
8+
title="Render guides"
9+
version="'3.0'"
10+
release="'3.0.0'"
11+
/>
12+
</guides>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Some Document
2+
=============
3+
4+
Project |project| in version |version|, release |release|.
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>Some Document - Render guides</title>
5+
6+
</head>
7+
<body>
18
<!-- content start -->
29
<div class="section" id="some-document">
310
<h1>Some Document</h1>
4-
5-
<p>Project Render guides in version 3.0, release 3.0.0.</p>
11+
12+
<p>Project Render guides in version 0.10, release 3.0.0.</p>
613

714
</div>
815
<!-- content end -->
16+
</body>
17+
</html>

tests/Integration/tests/meta/version-from-guides-xml/input/guides.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
>
77
<project
88
title="Render guides"
9-
version="'3.0'"
9+
version="0.10"
1010
release="3.0.0"
1111
/>
1212
</guides>

0 commit comments

Comments
 (0)