Skip to content

[BUGFIX] Read project version from the DOM so "0.10" is not coerced to 0.1#1345

Open
CybotTM wants to merge 1 commit into
phpDocumentor:mainfrom
netresearch:fix/xml-version-string-coercion
Open

[BUGFIX] Read project version from the DOM so "0.10" is not coerced to 0.1#1345
CybotTM wants to merge 1 commit into
phpDocumentor:mainfrom
netresearch:fix/xml-version-string-coercion

Conversation

@CybotTM

@CybotTM CybotTM commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Problem

A guides.xml with <project version="0.10"> is rendered with the version 0.1 (title, objects.inv, every |version| substitution). Any round / trailing-zero two-part version is mangled:

guides.xml parsed as
0.10 0.1
1.0 1
1.10 1.1
13.0 13
0.9, 13.4, 1.2.3, main unchanged

It surfaced on docs.typo3.org for netresearch/nr-vault and netresearch/nr-llm, whose 0.10 / 0.12 releases were published under 0.1.

Cause

XmlFileLoader parses guides.xml with XmlUtils::convertDomElementToArray(), which runs phpize() on every attribute value. phpize("0.10") returns the float 0.1 (it is is_numeric), which then stringifies to "0.1".

There was already a workaround — an escaped version syntax (version="'3.0'", single-quoted to dodge phpize) plus a beforeNormalization that stripped the quotes again. But that runs after phpize has already discarded the digit (0.100.1), so it can never recover it.

Fix

Read the <project> attributes (all strings) directly from the DOM, and detach the element before convertDomElementToArray() so phpize never touches them. The version is read correctly at the source, instead of being coerced and patched up afterwards. The <guides> attributes that genuinely want coercion (links-are-relative, max-menu-depth, …) are unaffected.

Because the root cause is fixed, the beforeNormalization workaround in the Symfony config is removed — escaping is no longer needed to write a correct version.

Backward compatibility

Projects that adopted the escaped version workaround for this very bug may still have <project version="'3.0'"> in their guides.xml. To keep those rendering 3.0 (and not the literal '3.0'), the surrounding single quotes are still stripped for version and release — the same trim($value, "'") the removed beforeNormalization did, now applied in XmlFileLoader when the attributes are read. New files don't need it: write the version directly, version="0.10" / version="3.0".

Before / after

<project version="0.10"> as loaded by XmlFileLoader:

Before

before

After

after

Tests

Two integration fixtures under tests/Integration/tests/meta/:

  • version-from-guides-xml — unescaped version="0.10" (with release="3.0.0" as a non-coerced control); asserts the rendered |version| stays 0.10. Passes with the fix and fails without it (without it: version 0.1).
  • version-from-guides-xml-quoted — the legacy quoted form version="'3.0'" / release="'3.0.0'"; asserts it still renders 3.0 / 3.0.0, covering the backward-compatibility path above.

Integration suite passes locally (228 tests). CI is green across PHP 8.1–8.3 (highest / locked / lowest): unit, integration, functional, Coding Standards, PHPStan and architecture checks.

@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch 2 times, most recently from ffab307 to fcc475c Compare June 16, 2026 22:01
@CybotTM CybotTM marked this pull request as draft June 17, 2026 05:38
@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch from fcc475c to 7d907c6 Compare June 17, 2026 05:51
@CybotTM CybotTM changed the title Keep version strings like "0.10" intact when loading guides.xml [BUGFIX] Read project version from the DOM so "0.10" is not coerced to 0.1 Jun 17, 2026
@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch 2 times, most recently from 6b70577 to 6503239 Compare June 17, 2026 06:19
@CybotTM CybotTM marked this pull request as ready for review June 17, 2026 06:28
@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch from 6503239 to c921c2c Compare June 18, 2026 20:11
@garvinhicking

Copy link
Copy Markdown
Contributor

Thanks - I can't really judge the impact of this and hope @jaapio can give some feedback. I remember having stabbed at this and not being able to resolve this.

@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch from c921c2c to f346063 Compare June 18, 2026 21:21
…o 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>
@CybotTM CybotTM force-pushed the fix/xml-version-string-coercion branch from f346063 to c748708 Compare June 24, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants