WsdlToPhp / PackageGenerator

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

Give additional information and skip error and continue stub generation on PHP Fatal error: Uncaught InvalidArgumentException: Value "NULL" can't be used to get an object from ... #227

Closed tgerakitis closed 3 years ago

tgerakitis commented 3 years ago

Hi, when trying to import a WSDL (can provide example only directly and not here) I get the error below upon running the following code:

<?php
ini_set('display_errors', 1);
require './../../vendor/autoload.php';

use WsdlToPhp\PackageGenerator\ConfigurationReader\GeneratorOptions;
use WsdlToPhp\PackageGenerator\Generator\Generator;

// Options definition: the configuration file parameter is optional
$options = GeneratorOptions::instance(/* '/path/file.yml' */);
$options
    ->setOrigin('https://some.url/wsdl')
    ->setDestination(__DIR__ . '/SomeServices/Premium')
    ->setComposerName('Someintegrations/Some')
    ->setSoapOptions([
        'encoding' => 'UTF-8',
        'user_agent' => 'SomeSomeSoap/1.0.0',
        'exceptions ' => true,
        #'cache_wsdl' => WSDL_CACHE_NONE,
        'features' => SOAP_SINGLE_ELEMENT_ARRAYS
    ]);
// Generator instantiation
$generator = new Generator($options);
// Package generation
$generator->generatePackage();

Am I doing something wrong? Is there a way to catch this error and to continue generating the stubs? The error is not giving me any information on what part of the WSDL is causing the issue. It might simply be a part of a service that I don't need anyways.

PHP Fatal error:  Uncaught InvalidArgumentException: Value "NULL" can't be used to get an object from "WsdlToPhp\PackageGenerator\Container\Model\Struct" in /app/vendor/wsdltophp/packagegenerator/src/Container/AbstractObjectContainer.php:161
Stack trace:
#0 /app/vendor/wsdltophp/packagegenerator/src/Container/Model/Struct.php(100): WsdlToPhp\PackageGenerator\Container\AbstractObjectContainer->get()
#1 /app/vendor/wsdltophp/packagegenerator/src/Container/Model/Struct.php(28): WsdlToPhp\PackageGenerator\Container\Model\Struct->get()
#2 /app/vendor/wsdltophp/packagegenerator/src/Generator/Generator.php(202): WsdlToPhp\PackageGenerator\Container\Model\Struct->getStructByName()
#3 /app/vendor/wsdltophp/packagegenerator/src/File/Service.php(291): WsdlToPhp\PackageGenerator\Generator\Generator->getStructByName()
#4 /app/vendor/wsdltophp/packagegenerator/src/File/OperationAnnotationBlock.php(170): WsdlToPhp\PackageGenerator\File\Service::getOperationMethodReturnType()
#5 /app/vendor/wsdltophp/packagegenerator/src/File/OperationAnnotat in /app/vendor/wsdltophp/packagegenerator/src/Container/AbstractObjectContainer.php on line 161

Fatal error: Uncaught InvalidArgumentException: Value "NULL" can't be used to get an object from "WsdlToPhp\PackageGenerator\Container\Model\Struct" in /app/vendor/wsdltophp/packagegenerator/src/Container/AbstractObjectContainer.php on line 161

InvalidArgumentException: Value "NULL" can't be used to get an object from "WsdlToPhp\PackageGenerator\Container\Model\Struct" in /app/vendor/wsdltophp/packagegenerator/src/Container/AbstractObjectContainer.php on line 161

Call Stack:
    0.2050     349424   1. {main}() /app/components/soap/wsdl-to.php:0
    1.3419    3420904   2. WsdlToPhp\PackageGenerator\Generator\Generator->generatePackage() /app/components/soap/wsdl-to.php:27
  107.6853    7641168   3. WsdlToPhp\PackageGenerator\Generator\Generator->doGenerate() /app/vendor/wsdltophp/packagegenerator/src/Generator/Generator.php:183
  107.6853    7641168   4. WsdlToPhp\PackageGenerator\Generator\GeneratorFiles->doGenerate() /app/vendor/wsdltophp/packagegenerator/src/Generator/Generator.php:170
  163.3917   10551624   5. WsdlToPhp\PackageGenerator\Generator\GeneratorFiles->generateServicesClasses() /app/vendor/wsdltophp/packagegenerator/src/Generator/GeneratorFiles.php:41
  163.3969   10627528   6. WsdlToPhp\PackageGenerator\File\Service->write() /app/vendor/wsdltophp/packagegenerator/src/Generator/GeneratorFiles.php:83
  163.3969   10627528   7. WsdlToPhp\PackageGenerator\File\Service->writeFile() /app/vendor/wsdltophp/packagegenerator/src/File/AbstractFile.php:51
  163.3985   10629544   8. WsdlToPhp\PackageGenerator\File\Service->addClassElement() /app/vendor/wsdltophp/packagegenerator/src/File/AbstractModelFile.php:111
  163.3987   10629856   9. WsdlToPhp\PackageGenerator\File\Service->defineMethods() /app/vendor/wsdltophp/packagegenerator/src/File/AbstractModelFile.php:228
  163.4153   10644896  10. WsdlToPhp\PackageGenerator\File\Service->getMethodAnnotationBlock() /app/vendor/wsdltophp/packagegenerator/src/File/AbstractModelFile.php:296
  163.4153   10644992  11. WsdlToPhp\PackageGenerator\File\Service->addAnnotationBlockForOperationMethod() /app/vendor/wsdltophp/packagegenerator/src/File/Service.php:213
  163.4154   10645072  12. WsdlToPhp\PackageGenerator\File\OperationAnnotationBlock->addAnnotationBlockForOperationMethod() /app/vendor/wsdltophp/packagegenerator/src/File/Service.php:257
  163.4161   10648456  13. WsdlToPhp\PackageGenerator\File\OperationAnnotationBlock->addOperationMethodReturn() /app/vendor/wsdltophp/packagegenerator/src/File/OperationAnnotationBlock.php:24
  163.4161   10648584  14. WsdlToPhp\PackageGenerator\File\OperationAnnotationBlock->getOperationMethodReturnType() /app/vendor/wsdltophp/packagegenerator/src/File/OperationAnnotationBlock.php:161
  163.4162   10648584  15. WsdlToPhp\PackageGenerator\File\Service::getOperationMethodReturnType() /app/vendor/wsdltophp/packagegenerator/src/File/OperationAnnotationBlock.php:170  163.4162   10648584  16. WsdlToPhp\PackageGenerator\Generator\Generator->getStructByName() /app/vendor/wsdltophp/packagegenerator/src/File/Service.php:291
  163.4162   10648584  17. WsdlToPhp\PackageGenerator\Container\Model\Struct->getStructByName() /app/vendor/wsdltophp/packagegenerator/src/Generator/Generator.php:202
  163.4162   10648584  18. WsdlToPhp\PackageGenerator\Container\Model\Struct->get() /app/vendor/wsdltophp/packagegenerator/src/Container/Model/Struct.php:28
  163.4162   10648584  19. WsdlToPhp\PackageGenerator\Container\Model\Struct->get() /app/vendor/wsdltophp/packagegenerator/src/Container/Model/Struct.php:100
mikaelcom commented 3 years ago

The error can't be avoided, please send me the wsdl at contact@mikael-delsol.fr, thx

tgerakitis commented 3 years ago

hi @mikaelcom thank you very much. I've sent you the email, pls check your spam folder just in case. best, theo

tgerakitis commented 3 years ago

hi @mikaelcom pls let me know in case I can help! best theo

mikaelcom commented 3 years ago

It should be fixed.

Can you try using docker image from https://hub.docker.com/repository/docker/mikaelcom/wsdltophp? Or from phar file from https://github.com/WsdlToPhp/PackageGenerator/releases/tag/feature%2Fissue-227

tgerakitis commented 3 years ago

hey @mikaelcom, thank you, import works perfectly now.

I have a few different problems now with PHP stating:

{
    "name": "PHP Compile Error",
    "message": "Default value for parameters with a class type can only be NULL",
    "code": 64,
    "type": "yii\\base\\ErrorException",
    "file": "/app/components/pkg/premium/StructType/Payload.php",
    ...

The reason is that the generated code looks like this: (this is one simple example - this error is in __construct as well.

public function setHistory(\app\components\pkg\premium\StructType\History $history = 'no')
    {
        $this->history = $history;
        return $this;
    }

where the 'no' is supposed to be null.

I fixed it manually to see if it would work, there is still a problem with the request body because it adds a wrapping <parameter> which should be an <xxxLogin> element instead.

How it is supposed to look like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <xxxLogin>
         <request>
            <payload>
              ....

how it looks:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SOAP-ENV:Header />
    <SOAP-ENV:Body>
        <parameter>
            <request>
                <method />
                <payload>

I copied the generated body over to SoapUI and changed the parameterelement to xxxLogin and it worked fine.

My code:

$pkg = new pkg([
            AbstractSoapClientBase::WSDL_ENCODING => 'UTF-8',
            AbstractSoapClientBase::WSDL_USER_AGENT => 'CompanypkgSoap/1.0.0',
            AbstractSoapClientBase::WSDL_URL =>
            'https://www.mypkg.com/?wsdl',
            AbstractSoapClientBase::WSDL_URI =>'https://www.mypkg.com/',
            AbstractSoapClientBase::WSDL_CLASSMAP =>
            \app\components\pkg\premium\ClassMap::get(),
            AbstractSoapClientBase::WSDL_SOAP_VERSION => SOAP_1_1
        ]);
        $payload = new Payload();
        $payload->personId = $personId;
        $payload->clearingId = $clearingId;
        $payload->password = $password;
        $loginRequest = new Request();
        $loginRequest->payload = $payload;
        $response = $pkg->pkgLogin(new pkgLogin($loginRequest));
mikaelcom commented 3 years ago

hey @mikaelcom, thank you, import works perfectly now.

I have a few different problems now with PHP stating:

{
    "name": "PHP Compile Error",
    "message": "Default value for parameters with a class type can only be NULL",
    "code": 64,
    "type": "yii\\base\\ErrorException",
    "file": "/app/components/pkg/premium/StructType/Payload.php",
    ...

The reason is that the generated code looks like this: (this is one simple example - this error is in __construct as well.

public function setHistory(\app\components\pkg\premium\StructType\History $history = 'no')
    {
        $this->history = $history;
        return $this;
    }

where the 'no' is supposed to be null.

I'm going to fix it too indeed!

I fixed it manually to see if it would work, there is still a problem with the request body because it adds a wrapping <parameter> which should be an <xxxLogin> element instead.

How it is supposed to look like:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body>
      <xxxLogin>
         <request>
            <payload>
              ....

how it looks:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SOAP-ENV:Header />
    <SOAP-ENV:Body>
        <parameter>
            <request>
                <method />
                <payload>

I copied the generated body over to SoapUI and changed the parameterelement to xxxLogin and it worked fine.

My code:

$pkg = new pkg([
            AbstractSoapClientBase::WSDL_ENCODING => 'UTF-8',
            AbstractSoapClientBase::WSDL_USER_AGENT => 'CompanypkgSoap/1.0.0',
            AbstractSoapClientBase::WSDL_URL =>
            'https://www.mypkg.com/?wsdl',
            AbstractSoapClientBase::WSDL_URI =>'https://www.mypkg.com/',
            AbstractSoapClientBase::WSDL_CLASSMAP =>
            \app\components\pkg\premium\ClassMap::get(),
            AbstractSoapClientBase::WSDL_SOAP_VERSION => SOAP_1_1
        ]);
        $payload = new Payload();
        $payload->personId = $personId;
        $payload->clearingId = $clearingId;
        $payload->password = $password;
        $loginRequest = new Request();
        $loginRequest->payload = $payload;
        $response = $pkg->pkgLogin(new pkgLogin($loginRequest));

This issue is not due to the generator nor the generated package but due to the native SoapClient class that uses the WSDL to generate the XML request.

In your case, the xxxLogin element is defined in the WSDL such as:

<wsdl:message name="xxxLoginRequest">
  <wsdl:part name="parameter" element="xxxLogin"/>
</wsdl:message>

This is why SoapClient names the xxxLogin to parameter.

Renaming dynamically the parameter to the real parameter name is feasible by overriding the SoapClient in order to rewrite the XML request before it is actually sent.

mikaelcom commented 3 years ago

The default value is now fixed!

tgerakitis commented 3 years ago

@mikaelcom defaults look good, thank you I'm getting this error now when trying to set my first request: PHP Fatal error: Uncaught Error: Call to a member function __soapCall(

When running this code (no changes to other code parts, just wsdl to PHP generation and then running the same code):

$pkg = new pkg([
            AbstractSoapClientBase::WSDL_ENCODING => 'UTF-8',
            AbstractSoapClientBase::WSDL_USER_AGENT => 'CompanypkgSoap/1.0.0',
            AbstractSoapClientBase::WSDL_URL =>
            'https://www.mypkg.com/?wsdl',
            AbstractSoapClientBase::WSDL_URI =>'https://www.mypkg.com/',
            AbstractSoapClientBase::WSDL_CLASSMAP =>
            \app\components\pkg\premium\ClassMap::get(),
            AbstractSoapClientBase::WSDL_SOAP_VERSION => SOAP_1_1
        ]);
        $payload = new Payload();
        $payload->personId = $personId;
        $payload->clearingId = $clearingId;
        $payload->password = $password;
        $loginRequest = new Request();
        $loginRequest->payload = $payload;
        $response = $pkg->pkgLogin(new pkgLogin($loginRequest));

About the SoapClient

Renaming dynamically the parameter to the real parameter name is feasible by overriding the SoapClient in order to rewrite the XML request before it is actually sent.

Can I simply use the class you've linked to or do I actually need to write my own wrapper?

mikaelcom commented 3 years ago

@mikaelcom defaults look good, thank you I'm getting this error now when trying to set my first request: PHP Fatal error: Uncaught Error: Call to a member function __soapCall(

When running this code (no changes to other code parts, just wsdl to PHP generation and then running the same code):

$pkg = new pkg([
            AbstractSoapClientBase::WSDL_ENCODING => 'UTF-8',
            AbstractSoapClientBase::WSDL_USER_AGENT => 'CompanypkgSoap/1.0.0',
            AbstractSoapClientBase::WSDL_URL =>
            'https://www.mypkg.com/?wsdl',
            AbstractSoapClientBase::WSDL_URI =>'https://www.mypkg.com/',
            AbstractSoapClientBase::WSDL_CLASSMAP =>
            \app\components\pkg\premium\ClassMap::get(),
            AbstractSoapClientBase::WSDL_SOAP_VERSION => SOAP_1_1
        ]);
        $payload = new Payload();
        $payload->personId = $personId;
        $payload->clearingId = $clearingId;
        $payload->password = $password;
        $loginRequest = new Request();
        $loginRequest->payload = $payload;
        $response = $pkg->pkgLogin(new pkgLogin($loginRequest));

Please send me the real values by email, I don't see any error regarding the generated package

About the SoapClient

Renaming dynamically the parameter to the real parameter name is feasible by overriding the SoapClient in order to rewrite the XML request before it is actually sent.

Can I simply use the class you've linked to or do I actually need to write my own wrapper?

You have to write your own, tricky in your case I must admit.

tgerakitis commented 3 years ago

Hi @mikaelcom,

again about the fatal error: It does not seem to have anything to do with the values that I use. I get the same error with empty string values.

I guess the problem lies somewhere in the generation - I may be doing something wrong here: This is the docker-compose.yml that I used to generate my package

  wsdltophp:
    image: mikaelcom/wsdltophp:feature-issue-227
    volumes:
      - "./app/:/app/"
    command: >
      generate:package
        --urlorpath="https://www.mypkg.com/?wsdl"
        --namespace="app\components\pkg\premium"
        --destination="/app/components/pkg/premium"
        --src-dirname=""
        --gentutorial
        --standalone=false
        --force

I'm using the framework yii2 which autoloads according to PSR and finds the namespaced class without any problem.

The error gets thrown here:

/**
 * This class stands for Pkg ServiceType
 * @subpackage Services
 */
class Pkg extends AbstractSoapClientBase
{
    /**
     * Method to call the operation originally named PkgLogin
     * Meta information extracted from the WSDL
     * - documentation: Login | Login
     * @uses AbstractSoapClientBase::getSoapClient()
     * @uses AbstractSoapClientBase::setResult()
     * @uses AbstractSoapClientBase::getResult()
     * @uses AbstractSoapClientBase::saveLastError()
     * @param \app\components\Pkg\premium\StructType\PkgLogin $PkgLogin
     * @return \app\components\Pkg\premium\StructType\PkgLoginResponse|bool
     */
    public function PkgLogin(\app\components\Pkg\premium\StructType\PkgLogin $PkgLogin)
    {
        try {
            // this line below causes Exception: Error: Call to a member function __soapCall() on null
            $this->setResult($this->getSoapClient()->__soapCall('PkgLogin', array(
                $PkgLogin,
            ), array(), array(), $this->outputHeaders));

            return $this->getResult();
        } catch (\SoapFault $soapFault) {
            $this->saveLastError(__METHOD__, $soapFault);
            return false;
        }
    }
mikaelcom commented 3 years ago

Then I think you wrongly instantiate and use the service class.

Can you show how you instantiate and use this service class?

tgerakitis commented 3 years ago

Hi @mikaelcom ,

this is my code:

$pkg = new Pkg([
            AbstractSoapClientBase::WSDL_ENCODING => 'UTF-8',
            AbstractSoapClientBase::WSDL_USER_AGENT => 'CompanypkgSoap/1.0.0',
            AbstractSoapClientBase::WSDL_URL =>
            'https://www.mypkg.com/?wsdl',
            AbstractSoapClientBase::WSDL_URI =>'https://www.mypkg.com/',
            AbstractSoapClientBase::WSDL_CLASSMAP =>
            \app\components\pkg\premium\ClassMap::get(),
            AbstractSoapClientBase::WSDL_SOAP_VERSION => SOAP_1_1
        ]);
        $payload = new Payload();
        $payload->personId = $personId;
        $payload->clearingId = $clearingId;
        $payload->password = $password;
        $loginRequest = new Request();
        $loginRequest->payload = $payload;
        $response = $pkg->pkgLogin(new pkgLogin($loginRequest));
mikaelcom commented 3 years ago

This is details but why do you specify these parameters:

Is it necessary?

Anyway, even with these parameters, I succeed to call the WS, I'll email my script, you'll tell me :wink:

tgerakitis commented 3 years ago

hi @mikaelcom thanks for your help, it seems it was a configuration issue on my side. Best, Theo