How to set ComplexType from a php class

Hi, I am trying to define a complexType to return as a SOAP response but I always received the standard xsi:type=“SOAP-ENC:Struct” although I have defined the complexType in XSD and added it in wsdl before create the soap server, something is missed or any clear sample to do something similar?

my code in laravel
//Instantiation for WSDL mode
$wsdl = new Wsdl(‘InfrastuctureService’,‘wsdl/Infrastructure.wsdl’);
$wsdl->addComplexType(DepartmentType::class);
$server = new SoapServer($wsdl, [‘cache_wsdl’ => WSDL_CACHE_NONE]);
$server = new SoapServer(null, $soapClientOptions);
$server->setReturnResponse(true);
$server->setClass(InfrastructureController::class);

    $soapResponse = $server->handle();        

    return response()->make($soapResponse)->header('Content-Type', 'application/xml');
}

/**
 * Retrieve a department by ID.
 *
 * @param int $departmentId The ID of the department to retrieve.
 * @return DepartmentType The department data.
 */
public function getDepartment($departmentId)
{
    $department = department::where('id', $departmentId)->firstOrFail();
    $departmentype = new DepartmentType($department->name, "phone", $departmentId, 5);
    return $departmentype;
}

response from server
GetDepartmentResponse>

Donnell Moen II
phone
1
5

</ns1:GetDepartmentResponse>

complexType defined in xsd
<xs:complexType name=“DepartmentType”>
xs:sequence
xs:sequence
<xs:element ref=“DepartmentName”/>
<xs:element ref=“DepartmentPhone” maxOccurs=“unbounded”/>
</xs:sequence>
</xs:sequence>
<xs:attribute name=“DeptartID” type=“xs:ID” use=“required”/>
<xs:attribute name=“useWard” type=“xs:IDREF”/>
</xs:complexType>

Thanks in advance

Welcome to the forum!

Why are you creating the second instance? Due to you creating the second instance you are using an instance without your complex type being passed in.

Thanks, I saw it yesterday, now I got error to load wsdl, any idea if it is about client_options or other parameter to configure?

SOAP-ERROR: Parsing WSDL: Couldn’t load from ‘wsdl/Infrastructure.wsdl’ : failed to load external entity “wsdl/Infrastructure.wsdl”

I wish I could help further but I am not familiar with that particular component. Hopefully one of the folks that is familiar with it will post an answer soon.

There are many possible reasons when acessing wsdl files when initializing soap server instances. You have to know, that the php soap implementation is strict. It does not forgive mistakes. If the web service definitions are not written correctly, PHP will definitely tell you in the form of an error.

You can test, if the wsdl file is accessible and really stored under the given path. Without knowing what exactly is the content of the wsdl file, its hard to say what the issue is.

Yes, I was checking everything, path, content wsdl, use other wsdl, change client options… the code is here
soapserver
line with wsdl

I could not find any sample to follow …

thanks for the answers

Since you have a data object called DepartmentType you can publish it in the classmap option of your soap server class.

The data object represents a complex type

As you already stated out that there is a complex type defined in an xsd, the way to write a data object is the way to go. As written in the official PHP documentation, wether SOAP server nor SOAP client know nothing about complex types and a mapping on php data objects. You have to set the classmap option when initializing a server or a client. I can’t judge what exactly Laravel does there. I don’t use Laravel and I think that Laravel shouldn 't be the point since PHP SOAP is easier to understand without the use of any framework and focusses on the standards.

How to do it without a framework I 've described some years ago on a stack overflow question. Beside that here 's a small example package that shows how to consume a publicly available isbn soap webservice.

// better work with a fully qualified uri here or simply make sure that the specified
// path is accessible.  (@example: file_get_contents(__DIR__ . '/wsdl/file.wsdl'));
$wsdl = 'https://domain.tld/path/somewsdlfile.wsdl';

$server = new \SoapServer($wsdl, [
    'classmap' => [
        'ns:yourComplexTypeName' => \Fully\Qualified\Class\Name::class,
    ],
]);

$client = new \SoapClient($wsdl, [
    'classmap' => [
        'ns:yourComplexTypeName' => \Fully\Qualified\Class\Name::class,
    ],
]);

Since the wsdl file in the package you linked here is hidden in a deeply nested folder structure, I 'd test again, if the file is accessible from within the class you initialize your SOAP server or SOAP client. The best advice here is to use a given path constant or define an uri, from where the wsdl file is accessible from. It 's mendatory that a wsdl file is publicly available. It absolutely makes no sense to store a webservice definition somewhere you think it 's protected. For protecting your webservice just use WSS standards. If you don 't want to make your wsdl file publically accessible, make sure that your implementation prints out the webservice definition when calling an uri like http://domain.tld/webservice?wsdl. When the PHP soap server class was initialized in WSDL mode, the wsdl parameters is interpreted automatically (when your wsdl file is valid).

Keep your WSDL tidy

Since a webservice description is elemental for SOAP client and SOAP server instances, you should do everything on writing a valid webservice definition. Here 's a small example, what can cause an error on initializing SOAP server and SOAP client classes.

<wsdl:service name="InfrastuctureService">
    <wsdl:port name="InfrastucturePort" binding="tns:InfrastuctureBinding">
        <soap:address location="http://hospital.example.com/api/soap/infrastucture-service"/>
    </wsdl:port>
</wsdl:service>

This is a part from your infrastructure.wsdl file. The given soap address for your webservice looks like its not accessible because it does not exist. You must ensure that the address given here can be reached. If it is an unreachable address, the initialisation of your SOAP server or SOAP client class can fail. Alternatively you can use the location option when initializing a SOAP client class to overwrite the given location parameter from the wsdl file.

After all …

All the written advices are just guessing since it 's not reproducable what Laravel does here. I testet your wsdl locally with just initializing a SOAP client and a SOAP server class and there were no errors thrown (send_errors and èxceptions options are set / all relevant files were stored in the same directory / all types and functions were printed out). In the end, I can only repeat myself. Try to get your web service up and running without a framework first. Just to reduce the complexity a little.