WsdlToPhp / PackageGenerator

Generates a PHP SDK based on a WSDL, simple and powerful, WSDL to PHP
https://providr.io
MIT License
418 stars 73 forks source link

Setting to make constructor arguments optional #275

Closed mwolff-fn closed 1 year ago

mwolff-fn commented 1 year ago

The problem

We have a lot of legacy code that needs updating to the latest version of PackageBase/PackageGenerator. Because the SOAP services we're using have lots and lots of arguments, many of which are optional, we almost never passed the arguments to the class constructor. Instead, we created an empty instance and then only set the relevant arguments via setters. This has never been a problem.

With the new PackageGenerator (currently 4.1.5), the class constructors are now created differently: If the WSDL says some property is mandatory, then it is no longer optional for passing via the constructor, so all our legacy code will now break. We could rewrite it, but then lots of our code would look a bit like this:

$object = new ProxyClass(
    $arg1, null, null, null, null, null, null, null, $arg2, null, null, null, null, null, null, $arg3
);

...while we would prefer to keep it like this to maintain sanity:

$object = new ProxyClass();
$object->setArg1($arg1)
    ->setArg2($arg2)
    ->setArg3($arg3);

The "pass everything via constructor" approach also fails when the argument order changes between versions of the WSDL file.

Possible solutions

a) Introduce a new generator setting like "optional_constructor_arguments" which is false by default and will allow constructor arguments to remain optional even if the property is defined as mandatory by the WSDL when set to true.

or

b) Introduce some generator hook methods that allow intercepting the generation of certain nodes and to customize the generated output.

Possible alternatives

With PHP8 we could use named arguments instead, but since we're dealing with legacy code, we need the classes to work with both PHP7.4 and >= 8.0 for a smooth transition.

Another alternative might be to turn off validation during the transition period, but we're not ready to give that up ;-)

Additional context

Example for how a constructor looked when generated with a previous version:

class FindLogin extends AbstractStructBase
{
    /**
     * The login
     * Meta information extracted from the WSDL
     * - maxOccurs: 1
     * - minOccurs: 1
     * @var \Proxy\Struct\Login
     */
    public $login;

    // ...more properties

   public function __construct(\Proxy\Struct\Login $login = null, ...more arguments)

...and here's what it looks like now:

class FindLogin extends AbstractStructBase
{
    /**
     * The login
     * Meta information extracted from the WSDL
     * - maxOccurs: 1
     * - minOccurs: 1
     * @var \Proxy\Struct\Login
     */
    protected \Proxy\Struct\Login $login;

    // ...more properties

    public function __construct(\Proxy\Struct\Login $login, ...more arguments)

Are there any other solutions I may have missed?

mikaelcom commented 1 year ago

Hi, Thanks for your feedback. Before starting for any development, have you tried this approach demonstrated at https://3v4l.org/hK2ZR? Let me know if it would fit your needs.

mikaelcom commented 1 year ago

Closed too fast before your answer ;)

mwolff-fn commented 1 year ago

Hi Mikaël,

thanks for the suggestion, didn't think about that - it would work for sure, but would still require a lot of changes on our part. That doesn't matter much though as I also found a rather trivial solution that we're probably going to go with: Adding another script to the build process, performing a second pass over the generated classes and changing the constructor arguments. That way, we wouldn't need to change anything in our codebase at all.

So, two possible solutions available - no need for any new feature in the PackageGenerator :-)

Thanks for your input, much appreciated!