Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unsignedInt type not supported #504

Closed
RosskoDCA opened this issue Mar 6, 2024 · 14 comments
Closed

unsignedInt type not supported #504

RosskoDCA opened this issue Mar 6, 2024 · 14 comments

Comments

@RosskoDCA
Copy link

RosskoDCA commented Mar 6, 2024

Q A
Version 3.1.1

Support Question

I tried fixed this in this PR but it didn't work. I am not sure, if this is an issue or future request or something else, so I am asking for support.

There's WSDL document in attachment (I hope I clean up that file correctly) where is xs type unsignedInt

For now my config looks like this:

$options = ExtSoapOptions::defaults($wsdl, [
    'login' => '...',
    'password' => '...',
])->withClassMap(RonClassmap::getCollection())->withTypeMap(RonTypemap::getCollection());

return Config::create()
    ->setEngine($engine = DefaultEngineFactory::create($options))
    ->setTypeDestination('src/TerminalData/Type')
    ->setTypeNamespace('App\TerminalData\Type')
    ->setClientDestination('src/TerminalData')
    ->setClientNamespace('App\TerminalData')
    ->setClassMapName('TerminalDataClassmap')
    ->setClassMapDestination('src/TerminalData')
    ->setClassMapNamespace('App\TerminalData')
    ->addRule(new Rules\AssembleRule(new StrictTypesAssembler()))
    ->addRule(new Rules\AssembleRule(new Assembler\FinalClassAssembler()))
    ->addRule(new Rules\AssembleRule(new Assembler\FluentSetterAssembler()))
    ->addRule(new Rules\AssembleRule(new Assembler\GetterAssembler(
        (new Assembler\GetterAssemblerOptions())
            ->withDocBlocks(false)
            ->withBoolGetters()
            ->withOptionalValue()
    )))
    ->addRule(new Rules\AssembleRule(new PropertyAssembler(
        (new Assembler\PropertyAssemblerOptions())
            ->withDocBlocks(false)
            ->withTypeHints()
            ->withOptionalValue()
    )))
    ->addRule(new Rules\AssembleRule(new Assembler\ImmutableSetterAssembler(
        (new Assembler\ImmutableSetterAssemblerOptions())
            ->withDocBlocks(false)
    )))
    ->addRule(
        new Rules\IsRequestRule(
            $engine->getMetadata(),
            new Rules\MultiRule([
                new Rules\AssembleRule(new Assembler\RequestAssembler()),
                new Rules\AssembleRule(new Assembler\ConstructorAssembler(new Assembler\ConstructorAssemblerOptions())),
            ])
        )
    )
    ->addRule(
        new Rules\IsResultRule(
            $engine->getMetadata(),
            new Rules\MultiRule([
                new Rules\AssembleRule(new Assembler\ResultAssembler()),
            ])
        )
    )
    ->addRule(
        new Rules\IsExtendingTypeRule(
            $engine->getMetadata(),
            new Rules\AssembleRule(new Assembler\ExtendingTypeAssembler())
        )
    )
    ->addRule(
        new Rules\IsAbstractTypeRule(
            $engine->getMetadata(),
            new Rules\AssembleRule(new Assembler\AbstractClassAssembler())
        )
    )
;

that classmap is generated and typemap is basically the same as default one, but I added custom type for DateTime (I was dealing with this in past, the dateTime converter converts the XML to attribute with name <dateTime> but I needed <dateTimeFrom> etc.)

When I run the types generate command, it generates that unsignedInt type like

private ?\App\TerminalData\Type\UnsignedInt $relayMask = null;

because of this \Phpro\SoapClient\CodeGenerator\Model\Property::getType the 'usnignedInt' is not "knownType"

But it is native soap type also, which means, we can not find definition in WSDL. Now I do not know how to avoid this. I tried and succeed overriding the PropertyAssember to my own and with some dirty hack I changed that unsignedInt to int or mixed, it doesn't metter, but then I realize there's getter & setter with App\TerminalData\Type\UnsignedInt type also. I do not want to rewrite those assemblers too.

To show I just exhaust all the options, now I have added new rule in config:

->addRule(
        new Rules\PropertynameMatchesRule(
            new Rules\MultiRule([
                new Rules\AssembleRule(
                    new PropertyAssembler(
                        (new Assembler\PropertyAssemblerOptions())
                            ->withDocBlocks(false)
                            ->withTypeHints(false)
                            ->withOptionalValue()
                    )
                ),
                new Rules\AssembleRule(
                    new Assembler\FluentSetterAssembler(
                        (new Assembler\FluentSetterAssemblerOptions())
                            ->withDocBlocks(false)
                            ->withTypeHints(false)
                            ->withReturnType(false)
                    )
                ),
                new Rules\AssembleRule(
                    new Assembler\GetterAssembler(
                        (new Assembler\GetterAssemblerOptions())
                            ->withDocBlocks(false)
                            ->withBoolGetters(false)
                            ->withOptionalValue()
                    )
                ),
            ]),
            '/^relayMask$/'
        )
    )

which just remove the type from that one property. But I am not satisfied with this.

Is there a way to changed unsignedInt to something acceptable in PHP? I mean, there's range problem with native type int in PHP (in 32bit systems), there's logical problem with negative numbers, and there's also logical problem with decimal places if we map that type to float.

I hope I describe it understandable and I hope you can help me with this.

Daniel

attachment: terminal_data.zip

@veewee
Copy link
Contributor

veewee commented Mar 6, 2024

Thanks for reporting,

Can you swap:

    ->setEngine($engine = DefaultEngineFactory::create($options))

With

    ->setEngine($engine = CodeGeneratorEngineFactory::create(
        $options->getWsdl(),
        // Optional if you wanna load a local file instead of over HTTP : new FlatteningLoader(new StreamWrapperLoader())
    ))

As documented in the v3 changelog : https://github.com/phpro/soap-client/blob/v3.x/UPGRADING.md#v2-to-v3

For me, this generates:

    /**
     * @var int
     */
    private int $relayMask;

    /**
     * @return int
     */
    public function getRelayMask() : int
    {
        return $this->relayMask;
    }

    /**
     * @param int $relayMask
     * @return static
     */
    public function withRelayMask(int $relayMask) : static
    {
        $new = clone $this;
        $new->relayMask = $relayMask;

        return $new;
    }

(I've just used a configuration from an old project to quickly test, so the generated methods might be different from what you configured)

@RosskoDCA
Copy link
Author

@veewee Definitelly i can try, but the WSDL document (in my particular case) is behind basic auth. Can you help me how to pass the authentication ?

@veewee
Copy link
Contributor

veewee commented Mar 6, 2024

Something like this:

use Http\Client\Common\Plugin\AuthenticationPlugin;
use Http\Client\Common\PluginClient;
use Http\Discovery\Psr18ClientDiscovery;
use Http\Message\Authentication\BasicAuth;
use Soap\Psr18Transport\Wsdl\Psr18Loader;
use Soap\Wsdl\Loader\FlatteningLoader;


    ->setEngine($engine = CodeGeneratorEngineFactory::create(
        'http://yourremotewsdl',
        new FlatteningLoader(Psr18Loader::createForClient(
            new PluginClient(
                Psr18ClientDiscovery::find(),
                [
                    new AuthenticationPlugin(
                        new BasicAuth('username', 'password')
                    )
                ]
            )
        ))
    ))

@RosskoDCA
Copy link
Author

Great. It works perfectly. There's just one last issue, which I believe you will solve far more sooner than me. I am posting the whole unchanged WSDL in attachment.

The last thing is, it generates class TContractNumbers as:

<?php

declare(strict_types=1);

namespace App\TerminalData\Type;

use \App\TerminalData\Type\ArrayType;

final class TContractNumbers extends ArrayType
{
}

but that arrayType don't exists.

@veewee
Copy link
Contributor

veewee commented Mar 6, 2024

That looks like a bug in the code generation part indeed:

      <xs:complexType name="TContractNumbers">
        <xs:complexContent>
          <xs:restriction base="soapenc:Array">
            <sequence xmlns="http://www.w3.org/2001/XMLSchema"/>
            <xs:attribute ref="soapenc:arrayType" n1:arrayType="xs:string[]" xmlns:n1="http://schemas.xmlsoap.org/wsdl/"/>
          </xs:restriction>
        </xs:complexContent>
      </xs:complexType>

Results in

TContractNumbers
================

> urn:RON_PersonalData_Utils:TContractNumbers extends Array

+------------+--------------------------------------------------------------------+
| Meta       | Value                                                              |
+------------+--------------------------------------------------------------------+
| isAbstract | false                                                              |
| docs       |                                                                    |
| extends    | {                                                                  |
|            |     "type": "Array",                                               |
|            |     "namespace": "http:\/\/schemas.xmlsoap.org\/soap\/encoding\/", |
|            |     "isSimple": false                                              |
|            | }                                                                  |
+------------+--------------------------------------------------------------------+

Making the IsExtendingTypeRule kick in and extend Array (which get normalized to ArrayType since that is a reserved keyword)

The IsExtendingTypeRule should become smarter and skip some extensions like:

  • soapenc:array
  • enc12:array
  • apache:Map
  • ...

(reference - this logic is being used in the wsdl-reader : https://github.com/php-soap/wsdl-reader/blob/main/src/Metadata/Converter/Types/Rule/SkipArrayTypePropertiesRule.php. It's probably something to get rid of in the wsdl-reader part so that we get as good as possible meta-types and instead implement in here directly to make sure that those classes get ignored during code-generation in favour of regular array types.)

@RosskoDCA
Copy link
Author

Should I take a look and make PR?

@veewee
Copy link
Contributor

veewee commented Mar 6, 2024

Sure, feel free to provide a PR. We can see where to go from there.

@RosskoDCA
Copy link
Author

I am afraid I don't even know how to start. Unfortunately my soap experience is limited.

@veewee
Copy link
Contributor

veewee commented Mar 6, 2024

I can imagine, it's not an easy task to get started with I'm afraid.
Also, whilst commuting I figured the information on how to solve it is not an ideal solution because it generates the TContractNumbers type which should be infered to be considered an array - or even better - a list<string> and not a generated type class.

To fix the issue, it requires a couple of things:

Even though the 3 points above describe what needs to happen, it won't be very easy to cover all possible XSD configurations from the first try. As-in: it would probably take me around a day to fix this decently as well :)

@RosskoDCA
Copy link
Author

I have to ask. Is there any chance you would look at it in near future?

@veewee
Copy link
Contributor

veewee commented Mar 7, 2024

I'm a bit limited in spare-time at the moment, so don't expect this to land in the near future from my side.
However, if you want me to prioritize this, my work-time is for sale:

https://github.com/php-soap/.github/blob/main/HELPING_OUT.md#want-to-help-out-

Feel free to reach out by mail (soap at phpro.be) if you are intereset in investing this feature into the project.

@blessq12
Copy link

blessq12 commented Apr 1, 2024

i've faced with trouble on generate:classmap/types it return me an exeption with Expected "non-empty-string", got "string". How to fix that?

@veewee
Copy link
Contributor

veewee commented Apr 23, 2024

Added this specific array issue to the list for v4 at #485.
Closing this one for now.

@veewee veewee closed this as completed Apr 23, 2024
@veewee
Copy link
Contributor

veewee commented Jul 5, 2024

Hello there @RosskoDCA ,

I wanted to get back to this issue:
We are finishing up v4 of the soap-client package which uses a new encoding system internally.
With this new system, you should be able to get around this issue more easily.

We are eager to receive some early feedback on this new release.
If you got some time, feel free to play around with the alpha version:

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

No branches or pull requests

3 participants