Skip to content

feat(php): generate toXml()/fromXml()/builders for xml-encoded object types (TwiML) - #17795

Open
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1789762042-php-xml-twiml
Open

devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1789762042-php-xml-twiml

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Description

Linear ticket: Refs (none)

PHP counterpart of #17734 (Python), #17755 (Java), #17785 (TS), #17787 (C#) and #17792 (Go). Object types carrying IR xml encoding metadata (from #17732, IR 67.25.0) now generate XML serialization, parsing and fluent child builders — the TwiML helper-library surface.

$response = new Response();
$response->say('Hello', ['voice' => 'Polly.Joanna'])->break(['strength' => 'strong']);
$dial = $response->dial('+1555', ['record' => ['record-from-answer']]);
$dial->addNumber('+1444', ['sendDigits' => 'ww12']);   // `number` is Dial's text field → add-prefix
echo $response;   // <?xml version="1.0" encoding="UTF-8"?><Response><Say voice="Polly.Joanna">Hello<break strength="strong"/></Say>...

$parsed = Response::fromXml($xml);   // typed children, unknown attrs/children preserved

Changes Made

  • generators/php/base/src/asIs/Xml/*: new Core\Xml runtime (DOM/libxml only) — XmlElement generic node, XmlNode interface, XmlSerializableType base (extends JsonSerializableType, holds unknown XML attributes/children + addChild()), XmlUtils (secure parser rejecting DOCTYPE/external entities, root-name/namespace validation, scalar/enum/list parsing, wrapped-list merge of unknown content). Emitted only when the IR contains xml-encoded types; composer.json then also requires ext-dom/ext-libxml.
  • generators/php/model/src/object/XmlObjectGenerator.ts: for xml-encoded objects generates toXmlElement(), toXml(bool $xmlDeclaration = false), fromXml(string), fromXmlElement(XmlElement), __toString() (declaration included for root types only), and one builder per child type (say(Say|string|null $message = null, array $attributes = []): Say), with the shared add-prefix collision rule. Enum-typed values go through XmlUtils::parseEnum/enumValues so PHPStan keeps the enum literal unions in the generated array shapes.
  • ObjectGenerator.ts: xml objects extend XmlSerializableType instead of JsonSerializableType.
  • IR pin 67.21.067.25.0 for php-base/model/sdk.
  • New php-xml-twiml seed fixture (roots, nested children, attributes, namespaces/prefixes, wrapped lists, separator lists, enum lists, empty elements, 64-attr Wide, number/Number collision) registered in seed/php-sdk/seed.yml; changelog under generators/php/sdk/changes/unreleased/.
  • Updated README.md generator (not applicable)

Testing

  • Unit tests added/updated — XmlElementTest ships as a core test in generated SDKs.
  • Manual testing completed
    • pnpm turbo run compile --filter @fern-api/php-sdk: 18/18 tasks; biome clean.
    • pnpm seed test --generator php-sdk --fixture php-xml-twiml --skip-scripts --local: 1/1.
    • Generated SDK: composer install + PHPUnit OK (98 tests, 369 assertions) including a 13-case TwiML round-trip suite (builders, fromXml typed children, enum lists, wrapped lists, unknown attrs/children incl. prefixed x:extra, unknown wrapper content, Wide, empty elements, malformed/empty/wrong-root/wrong-namespace/DTD/invalid-enum/invalid-int errors); PHPStan exit 0 on src + tests.
    • exhaustive fixture regenerated: 0 xml-related diff (only pre-existing drift from main, reverted).

Known/shared limitation (same as the other languages): unknown children are re-emitted after typed children, so arbitrary mixed ordering isn't preserved.

Link to Devin session: https://app.devin.ai/sessions/311fe13ae5434245ada665a9b824809b
Open in Devin Desktop: https://app.devin.ai/desktop/session/311fe13ae5434245ada665a9b824809b?variant=devin


Devin Review

… types (TwiML)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

nitpickybot[bot]

This comment was marked as resolved.

cadesark and others added 2 commits September 18, 2026 21:23
…prefix unknown attrs, document namespace/text semantics

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Devin Review found 6 potential issues.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment thread generators/php/base/src/asIs/Xml/XmlUtils.Template.php
Comment thread generators/php/model/src/object/XmlObjectGenerator.ts Outdated
Comment thread generators/php/base/src/asIs/Xml/XmlUtils.Template.php
Comment thread generators/php/base/src/asIs/Xml/XmlUtils.Template.php
Comment thread generators/php/model/src/object/XmlObjectGenerator.ts
Comment thread generators/php/model/src/object/XmlObjectGenerator.ts Outdated
…teral validation, reject map properties

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docs Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-09-18T04:06:24Z).

Fixture main PR Delta
docs 266.3s (n=5) 263.1s (35 versions) -3.2s (-1.2%)

Docs generation runs fern generate --docs --preview end-to-end against the benchmark fixture with 35 API versions (each version: markdown processing + OpenAPI-to-IR + FDR upload).
Delta is computed against the nightly baseline on main.
Baseline from nightly run(s) on main (latest: 2026-09-18T04:06:24Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-09-18 22:27 UTC

@github-actions

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-09-18T04:06:24Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 82s (n=5) 113s (n=5) 60s -22s (-26.8%)
go-sdk square 124s (n=5) 295s (n=5) 147s +23s (+18.5%)
java-sdk square 187s (n=5) 268s (n=5) 154s -33s (-17.6%)
php-sdk square 65s (n=5) N/A 65s +0s (+0.0%)
python-sdk square 142s (n=5) 257s (n=5) 99s -43s (-30.3%)
ruby-sdk-v2 square 93s (n=5) 112s (n=5) 58s -35s (-37.6%)
rust-sdk square 181s (n=5) 204s (n=5) 150s -31s (-17.1%)
swift-sdk square 58s (n=5) 435s (n=5) 54s -4s (-6.9%)
ts-sdk square 136s (n=5) 139s (n=5) 108s -28s (-20.6%)

main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-09-18T04:06:24Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-09-18 22:28 UTC

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.

1 participant