Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Xsd2Php Laravel Package

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.

Deep Wiki
Context7

Getting Started

1. Split generator from runtime. The generator is a build-time tool; the runtime annotations/handlers ship to production:

composer require goetas-webservices/xsd2php-runtime
composer require --dev goetas-webservices/xsd2php

2. Write a namespace map. Every XSD targetNamespace you consume needs a PHP namespace, otherwise conversion aborts. config/xsd2php.yml:

namespaces:
  "http://schemas.example.com/order/v1":
    php_ns: ["Api", "Order", "Model"]
    alias: "Order"          # used for JMS type names / xsi:type resolution
  "":                       # chameleon / no-namespace schemas
    php_ns: ["Api", "Common", "Model"]

3. Run the CLI. -d is the PSR-4 root; the PHP namespace becomes the directory path underneath it:

vendor/bin/xsd2php convert config/xsd2php.yml resources/xsd/order.xsd -d src
# -> src/Api/Order/Model/PurchaseOrderType.php

Pass all entry-point XSDs on the command line; imported schemas are pulled in through their schemaLocation.

4. Deserialize a real payload immediately. Don't review generated code class-by-class — prove it works against a sample document from the API docs/partner:

$serializer = \JMS\Serializer\SerializerBuilder::create()->build();
$order = $serializer->deserialize($xml, \Api\Order\Model\PurchaseOrderType::class, 'xml');
echo $serializer->serialize($order, 'xml');

Where to look first: the repo's tests/ fixtures — they pair XSD snippets with the exact PHP/JMS output, which answers “what will xs:choice look like?” faster than any docs. Then bin/xsd2php, which is the canonical wiring of SchemaReader → PhpConverter → Psr4PathGenerator → writer if you need to drive it from PHP instead of the shell.

First use case: a single partner XSD (invoice, order, tracking) that you receive as XML over REST/SOAP. Generate models, deserialize, and stop hand-writing SimpleXMLElement traversal.

Implementation Patterns

Generate on demand, commit the output. Treat generated classes like compiled artifacts you check in: schema changes then show up as reviewable diffs, and CI can run xsd2php convert ... && git diff --exit-code src/Api to catch schemas that changed upstream without a regeneration.

"scripts": {
  "xsd2php": "xsd2php convert config/xsd2php.yml resources/xsd/order.xsd -d src"
}

Keep generation out of the hot path. Add the generated tree to PHPStan/PHPCS excludes and to coverage ignores; the docblock-and-public-property style will otherwise drown your own code in noise.

Compose with JMS, not with the SOAP client. The generated classes are plain JMS-serializable models — useful well beyond SOAP. For SOAP transport, goetas-webservices/soap-client consumes the same schema/config and reuses these classes as its message types, so one generation step serves both REST-ish XML endpoints and WSDL services.

Wrap access in a thin service layer. Put mapping quirks (defaults, denormalizing into your domain DTOs, currency/date normalization) in a hand-written service that takes the generated model in and returns a domain object. Generated classes stay regenerable; your business rules stay put.

Round-trip fixtures as your regression suite. Store one representative XML per schema version, deserialize → re-serialize, and compare with DOMDocument::C14N() so element ordering and whitespace don't cause false failures. This is the cheapest way to notice when a schema update silently stopped mapping a field.

Two-pass workflow for inherited types. For xs:extension-heavy schemas, generate once, then grep generated classes for extends to understand the PHP hierarchy before writing polymorphic handling (JMS discriminators key off the configured alias, so pick aliases deliberately — changing one later breaks xsi:type deserialization of stored payloads).

Gotchas and Tips

  • Missing namespace = hard failure. Any imported targetNamespace absent from the config throws during conversion. In practice the fix is to add the entry, not to fight the converter.
  • Copy the XSD tree intact. Relative schemaLocations resolve against the XSD's own directory. Flattening or renaming files (or pulling them from vendor/) breaks imports; remote http:// schemaLocations silently need local copies with rewritten imports.
  • alias collisions bite at runtime, not generation time. Two XSD namespaces mapping to the same class short-name produce ambiguous JMS type names, and xsi:type lookups resolve to the wrong class. Distinct aliases + distinct php_ns prevent it.
  • @JMS\XmlList(entry="...") is the element name, not the property name. Rename the PHP property freely; change entry and deserialization returns an empty array with no exception — the classic “my collection is always empty” bug.
  • Dates carry generated format strings. xs:date → DateTime<'Y-m-d'>, xs:dateTime → a full ISO format. If the remote party insists on a different representation, adjust at the boundary rather than editing the annotation.
  • xs:any / xs:anyType degrade to untyped values and won't round-trip as XML nodes without custom JMS handlers. Identify these early; they often justify a small hand-written class instead.
  • Enumerations are not PHP enums. Restricted simple types surface as plain strings/ints; validate them yourself if you need guarantees.
  • Nulls and empty elements need a serialization context. JMS drops nulls by default; use SerializationContext::create()->setSerializeNull(true) when the receiver requires present-but-empty elements, and check xsi:nil handling explicitly — it is not free.
  • Annotations on PHP 8 with JMS 3.x require doctrine/annotations to still be installed and the annotation reader enabled. If you upgrade the serializer major, verify a generated class still deserializes before regenerating everything.
  • Clear the serializer cache after regeneration. Stale JMS metadata in var/cache produces “type not found”/mismatched-property errors that look like converter bugs.
  • Never hand-edit generated files. They're overwritten on the next run. Subclassing is possible but re-annotating a subclass changes @XmlRoot/type names and can break discriminators — prefer services and accessors over subclass behavior.
  • Large schemas mean thousands of classes. Keep them in a dedicated namespace so autoloading, IDE indexing, and static analysis costs stay contained, and expect slow first-run composer dumps.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core