Convert XSD into PHP classes.
With goetas/xsd2php
you can convert any XSD/WSDL definition into PHP classes.
XSD2PHP can also generate JMS Serializer compatible metadata that can be used to serialize/unserialize the object instances.
There is one recommended way to install xsd2php via Composer:
- adding the dependency to your
composer.json
file:
"require": {
..
"goetas/xsd2php":"2.*@dev",
"goetas/xsd-reader":"2.*@dev",
"jms/serializer": "xsd2php-dev as 0.18.0",
..
}
"repositories": [{
"type": "vcs",
"url": "https://github.com/goetas/serializer.git"
}],
This package requires a patched version of JMS Serializer. In the last year the activity of JMS serializer was very low and some features required by this project was rejected or not yet reviewed ( #301, #222 )
With this example we will convert OTA XSD definitions into PHP classes.
Suppose that you have allo XSD files in /home/my/ota
.
vendor/bin/xsd2php convert:php \
`/home/my/ota/OTA_HotelAvail*.xsd \
--ns-map='http://www.opentravel.org/OTA/2003/05;Mercurio/OTA/2007B/' \
--ns-dest='Mercurio/OTA/2007B/;src/Mercurio/OTA/V2007B' \
--alias-map='http://www.opentravel.org/OTA/2003/05;CustomOTADateTimeFormat;Vendor/Project/CustomDateClass'
What about namespaces?
http://www.opentravel.org/OTA/2003/05
will be converted intoMercurio/OTA/2007B
PHP namespace
Where place the files?
Mercurio/OTA/2007B
classes will be placed intosrc/Mercurio/OTA/V2007B
directory
What about custom types?
--alias-map='http://www.opentravel.org/OTA/2003/05;CustomOTADateTimeFormat;Vendor/Project/CustomDateClass'
will instcut XSD2PHP to do not generate any class forCustomOTADateTimeFormat
type insidehttp://www.opentravel.org/OTA/2003/05
namespace. All reference to this type are replaced with theVendor/Project/CustomDateClass
class.
"scripts": {
"build": "xsd2php convert:php '/home/my/ota/OTA_HotelAvail*.xsd' --ns-map='http://www.opentravel.org/OTA/2003/05;Mercurio/OTA/2007B/' --ns-dest='Mercurio/OTA/2007B/;src/Mercurio/OTA/V2007B'"
}
Now you can build your classes with composer build
.
XSD2PHP can also generate for you JMS Serializer metadata that you can use to serialize/unserialize the generated PHP class instances.
vendor/bin/xsd2php convert:jms-yaml \
`/home/my/ota/OTA_HotelAvail*.xsd \
--ns-map='http://www.opentravel.org/OTA/2003/05;Mercurio/OTA/2007B/' \
--ns-dest='Mercurio/OTA/2007B/;src/Metadata/JMS;' \
--alias-map='http://www.opentravel.org/OTA/2003/05;CustomOTADateTimeFormat;Vendor/Project/CustomDateClass'
What about namespaces?
http://www.opentravel.org/OTA/2003/05
will be converted intoMercurio/OTA/2007B
PHP namespace
Where place the files?
http://www.opentravel.org/OTA/2003/05
will be placed intosrc/Metadata/JMS
directory
What about custom types?
--alias-map='http://www.opentravel.org/OTA/2003/05;CustomOTADateTimeFormat;Vendor/Project/CustomDateClass'
will instcut XSD2PHP to do not generate any metadata information forCustomOTADateTimeFormat
type insidehttp://www.opentravel.org/OTA/2003/05
namespace. All reference to this type are replaced with theVendor/Project/CustomDateClass
class. You have to provide a custom serializer for this type
use JMS\Serializer\SerializerBuilder;
use JMS\Serializer\Handler\HandlerRegistryInterface;
use Goetas\Xsd\XsdToPhp\Jms\Handler\BaseTypesHandler;
use Goetas\Xsd\XsdToPhp\Jms\Handler\XmlSchemaDateHandler;
$serializerBuiler = SerializerBuilder::create();
$serializerBuiler->addMetadataDir('metadata dir', 'DemoNs');
$serializerBuiler->configureHandlers(function (HandlerRegistryInterface $h) use ($serializerBuiler) {
$serializerBuiler->addDefaultHandlers();
$h->registerSubscribingHandler(new BaseTypesHandler()); // XMLSchema List handling
$h->registerSubscribingHandler(new XmlSchemaDateHandler()); // XMLSchema date handling
// $h->registerSubscribingHandler(new YourhandlerHere());
});
$serializer = $serializerBuiler->build();
// unserialize the XML into Demo\MyObject object
$object = $serializer->deserialize('<some xml/>', 'DemoNs\MyObject', 'xml');
// some code ....
// serialize bck the Demo\MyObject into XML
$newXml = $serializer->serialize($object, 'xml');
If your XSD contains xsd:anyType
or xsd:anySimpleType
types you have to specify a handler for this.
When you generate the JMS metadata you have to specify a custom handler:
bin/xsd2php.php convert:jms-yaml \
... various params ... \
--alias-map='http://www.w3.org/2001/XMLSchema;anyType;MyCustomAnyTypeHandler' \
--alias-map='http://www.w3.org/2001/XMLSchema;anyType;MyCustomAnySimpleTypeHandler' \
Now you have to create a custom serialization handler:
use JMS\Serializer\XmlSerializationVisitor;
use JMS\Serializer\XmlDeserializationVisitor;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\GraphNavigator;
use JMS\Serializer\VisitorInterface;
use JMS\Serializer\Context;
class MyHandler implements SubscribingHandlerInterface
{
public static function getSubscribingMethods()
{
return array(
array(
'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
'format' => 'xml',
'type' => 'MyCustomAnyTypeHandler',
'method' => 'deserializeAnyType'
),
array(
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'xml',
'type' => 'MyCustomAnyTypeHandler',
'method' => 'serializeAnyType'
)
);
}
public function serializeAnyType(XmlSerializationVisitor $visitor, $data, array $type, Context $context)
{
// serialize your object here
}
public function deserializeAnyType(XmlDeserializationVisitor $visitor, $data, array $type)
{
// deserialize your object here
}
}
Sometimes happen that you want not to have long class names but at the same time you want not too have namaing conflicts.
(example: MyNamesapce\UserElement
instead of MyNamesapce\User
or MyNamesapce\UserTypeType
instead of MyNamesapce\UserType
).
When you have an XSD with a type named User
, a type named UserType
and a root element named User
and UserElement
,
creating the right PHP classes names will be problemeatic. To solve this you have to choose the right naming strategy.
- If you don't not have naming conflicts and you want to have short and descriptive class names, use
--naming-strategy=short
option when you generate classes and metadata - If you have naming conflicts (or just you want to be stay safe) use
--naming-strategy=long
option when you generate classes and metadata. This will generate PHP classes with theElement
orType
suffix.
I'm sorry for the terrible english fluency used inside the documentation, I'm trying to improve it. Pull Requests are welcome.