goetas-webservices/xsd2php
Generate PHP classes from XSD schemas and WSDL files, converting XML Schema types into ready-to-use PHP models with JMS Serializer metadata support. A practical tool for building SOAP and XML integrations from existing contracts.
Architecture fit. xsd2php is a build-time code generator, not a runtime library. It does not belong in Laravel's service container, it ships no service provider or facade, and it should never execute during a request. Its correct place in a Laravel architecture is a CI/build step (or an artisan command invoked on demand) whose only output is a directory of plain PHP model classes. Those classes are POPOs — they do not extend Eloquent, they are not database-backed, and they should live outside app/Models to avoid confusing the domain layer. The package is a good fit only if the product genuinely speaks XML: a SOAP WSDL integration, an industry standard schema (UBL, OAGIS, ISO 20022, e-invoicing), or a partner XML feed. If the goal is REST/JSON, this is the wrong tool and should be rejected early.
Integration feasibility. Straightforward via Composer, and compatible with a modern Laravel stack. The real dependency chain matters more than the package itself: it requires goetas-webservices/xsd-reader, Symfony Console, and — for the mapping output — jms/serializer (plus doctrine/annotations on older configurations). JMS Serializer is a second serialization runtime sitting alongside Laravel's own, which is acceptable but is a deliberate architectural commitment. A thin artisan wrapper is roughly a day of work: read a config array of schema paths, invoke the generator's CLI/generator API, write into a configured output namespace.
Technical risk.
doctrine/annotations is effectively end-of-life. Generated output must target the right mapping style, otherwise the classes look correct and silently fail to (de)serialize.xsd:choice, substitution groups, xsd:any, and multi-namespace import/include chains map imperfectly to PHP types; expect manual patches to generated code, which then get overwritten on the next regeneration.Key questions before committing.
import/include across multiple namespace roots?goetas-webservices/soap-client acceptable, or does the vendor require a specific client (e.g. ext-soap WSDL mode)?Stack fit. Works with Laravel 10–12 on PHP 8.1+. The generated classes coexist harmlessly with Eloquent as a separate "integration model" namespace (e.g. App\Integrations\Acme\Generated). Recommended shape:
config/xsd2php.php — schema paths, output namespaces, mapping style, target directory.app/Console/Commands/GenerateXmlModelsCommand.php — artisan wrapper calling the underlying generator.app/Integrations/{Vendor}/ — hand-written service/client layer, DTO hydration, error mapping. Generated code is never edited by hand.--check / --dry-run mode for CI that fails the build if generated output differs from what is committed.Migration path. Do not retrofit an existing hand-written SOAP integration wholesale. Sequence it as: (1) a timeboxed spike — one schema, generate, round-trip a captured real payload through serialize/deserialize and assert on it; (2) if round-trip fidelity holds, wrap the generator in the artisan command and commit the first generated set; (3) build the hand-written client on top of the generated DTOs; (4) only then retire legacy hand-rolled XML marshalling. If step (1) fails on choice/any constructs, the honest outcome is to abandon the package and hand-write the DTOs — find that out in a week, not a quarter.
Compatibility watch-list. Pin the generator version exactly ("goetas-webservices/xsd2php": "x.y.z") — minor bumps in a code generator change output, and unpinned generators produce unreviewable diffs. Verify JMS Serializer mapping style against the installed major. Ensure doctrine/annotations is not required by a transitive path if running PHP 8.3+, since it will emit deprecations in test output.
Sequencing. Spike (3–5 days) → generator wrapper + config + CI drift check (2–3 days) → client/service layer (1–2 weeks depending on endpoint count) → payload fixture test suite → rollout behind a feature flag per integration. Budget a genuine 15–20% contingency for hand-patching generated edge cases; that is the normal experience with XSD codegen, not a failure signal.
Maintenance. Two distinct burdens. The package itself is low-churn and low-risk — a Composer-managed dev dependency updated a few times a year. The real burden is the generated artifact: it is a large volume of code in the repository that no one wrote, that reviewers cannot meaningfully read, and that changes en masse on any schema bump. Keep it in a dedicated directory, exclude it from static analysis and coverage, and never let it be hand-edited. Document the regeneration command prominently in the README; the most common failure is a new engineer editing generated files directly.
Support. MIT, community-only, no commercial backing, no SLA. Escalation path for a broken generator on an exotic schema is: fork it, or hand-write the affected classes. Both are viable at ~240 stars' worth of complexity, but budget for the fork scenario if the schema is non-trivial. This is acceptable for internal tooling and marginal for a customer-facing product with hard uptime commitments on the XML path.
Scaling. Codegen scales trivially — it is build-time. Runtime scaling concerns are the serializer: JMS Serializer with large XML documents (multi-MB, deeply nested) is memory-hungry and CPU-bound compared to JSON handling. If payloads are large, plan for streaming or chunked processing at the queue level rather than expecting request-cycle performance. Generated class count also matters — very large schemas (thousands of types) bloat autoloader and opcache, so consider excluding unused namespaces from generation.
Failure modes to instrument.
xsd:any and unknown elements are dropped without warning. Mitigate by diffing inbound XML element names against generated classes in a test, or logging unparsed nodes.Ramp-up. Low for the CLI itself; an artisan command and a config file is an afternoon. The actual learning curve is JMS Serializer's XML mapping semantics — what @XmlElement(namespace=...), @XmlList, and inheritance strategies actually mean in practice — plus the XSD constructs being mapped. That is a 1–2 day ramp for a PHP developer who has worked with SOAP or XML before, and closer to a week for someone who has not. The package docs are adequate for the happy path and thin on troubleshooting, so pair the initial spike with direct inspection of the generated output rather than expecting the docs to explain surprises.
How can I help you explore Laravel packages today?