v4 codegen: php type encoder
| Q | A |
|---|---|
| Version | 4.0.0-alpha1 |
Support Question
I've been trying to generate soap client type definitions with the built-in generator, but there seems to be no way to specify e.g \Cake\Chronos\Chronos instead of \DateTimeImmutable. (Phpro\SoapClient\CodeGenerator\Util\Normalizer is set to normalize simple types to hard-coded interfaces)
I can specify custom SimpleType encoders for the client, but not for generating a client. :)
Err, it was a bad example as \Cake\Chronos\Chronos implements \DateTimeInterface, so there would be no conflict.
I meant to say eg:
-
\Cake\Chronos\ChronosDateinstead of\DateTimeInterfaceforxsd:date -
\Decimal\Decimalinstead offloatforxsd:decimalandxsd:double.
Here's the weird thing. I was able to change php types for date or datetime fields, but for decimal it doesn't work.
I tried to write xsd as:
<xsd:element name="amount" type="xsd:decimal"/>
and as:
<xsd:element name="amount">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="3"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
Neither of them works, it just comes back as either float or mixed.
My DecimalReplacer:
final class DecimalReplacer implements TypeReplacer
{
public function __invoke(XsdType $xsdType): XsdType
{
if (!$this->isDecimalType($xsdType)) {
return $xsdType;
}
return $xsdType->copy(Decimal::class);
}
private function isDecimalType(XsdType $type): bool
{
$checks = [
new IsOfType('http://www.w3.org/2001/XMLSchema', 'decimal'),
new IsOfType('http://www.w3.org/2001/XMLSchema', 'double'),
];
return any($checks, static fn (IsOfType $check): bool => $check($type));
}
}
Another odd issue is that for datetime replacer, if I use a class like Chronos, it will be changed correctly:
/**
* @var \Cake\Chronos\Chronos
*/
protected \Cake\Chronos\Chronos $from;
/**
* @var \Cake\Chronos\Chronos
*/
protected \Cake\Chronos\Chronos $to;
But if I use \DateTimeImmutable, then the php type will be generated as mixed:
/**
* @var mixed
*/
protected mixed $from;
/**
* @var mixed
*/
protected mixed $to;
My DateTimeReplacer:
final class DateTimeReplacer implements TypeReplacer
{
public function __construct(
private ?IsOfType $check = null,
) {
$this->check ??= new IsOfType('http://www.w3.org/2001/XMLSchema', 'dateTime');
}
public function __invoke(XsdType $xsdType): XsdType
{
if (!($this->check)($xsdType)) {
return $xsdType;
}
return $xsdType->copy(Chronos::class);
}
}
I thought the issue could come from classes being native (\DateTimeImmutable is native, \Decimal\Decimal comes from extension), but the decimal issue persists no matter what type I set.
Hello @rauanmayemir,
About your first question: \DateTimeImmutable seems to work here. Do note that you need to prefix it with a backslash since it is in the PHP internal space.
The Decimal class is indeed not working. I'll have to dig into the specifics, but I suppose it is because the name of the class (without namespace) is "Decimal" which is reserverd for the translation of xsd:decimal to float in \Phpro\SoapClient\CodeGenerator\Util\Normalizer::$normalizations.
You mean normalizer is stripping the namespace part and using the base class name?
I tried doing return $xsdType->copy('\\Decimal\\Decimal');, but it still failed.
I mean the problem is that the class name is Decimal. If you change it to Decimal2 it works.
This is because the information gets normalized again in the constructor:
https://github.com/phpro/soap-client/blob/8946e9cd3537a0d2d77c49e8b882c48ee38f8d45/src/Phpro/SoapClient/CodeGenerator/Model/Property.php#L50-L57
I'll have to find away to avoid that unnecessary normalization