Viewed   136 times

I'm preparing the SOAP server and generating my WSDL using the follow code:

//(... Controller action code ...)
if (key_exists('wsdl', $params)) {
    $autodiscover = new AutoDiscover();
    $autodiscover->setClass('WebServiceClass')
                 ->setUri('http://server/webserver/uri');
    $autodiscover->handle();
} else {
    $server = new Server(null);
    $server->setUri($ws_url);
    $server->setObject($this->getServiceLocator()->get('MyControllerServiceWebServiceClass'));
    $server->handle();
}

//(... Controller action code ...)

But in one of my WebService method I have a parameter of type Array in which each element is of type "MyOtherClass", like follows:

    /**
     * Add list of MyOtherClass items
     *
     * @param MyOtherClass[]    $items
     *
     * @return bool
     */
    function add($items) {
        // Function code here
    }

When I try to generate the WSDL I get the follow error:

PHP Warning:  DOMDocument::loadXML(): Empty string supplied as input in /<zend framweork path>/Server/vendor/zendframework/zendframework/library/Zend/Soap/Server.php on line 734

Or this Exception:

Cannot add a complex type MyOtherClass[] that is not an object or where class could not be found in "DefaultComplexType" strategy.

When I added to my code something like this:

//(...)
if (key_exists('wsdl', $params)) {

    $autodiscover = new AutoDiscover();
    $autodiscover->setClass('WebServiceClass');
    $autodiscover->setUri($ws_url);

    $complex_type_strategy = new ZendSoapWsdlComplexTypeStrategyArrayOfTypeComplex();
    $complex_type_strategy->addComplexType('MyOtherClass');
    $autodiscover->setComplexTypeStrategy($complex_type_strategy);
    $autodiscover->handle();
} else {
//(...)

I get the follow error message:

Fatal error: Call to a member function getTypes() on a non-object in /<project dir>/vendor/zendframework/zendframework/library/Zend/Soap/Wsdl/ComplexTypeStrategy/AbstractComplexTypeStrategy.php on line 54

In resume, the question is: how can I make aware the WSDL of the new Custom Type used as parameter?

Thanks

 Answers

4

I did something similar and this is a sample code:

/* code.... */
if (array_key_exists('wsdl', $this->request->getQuery()) || array_key_exists('WSDL', $this->request->getQuery())) {

                    $auto = new ZendSoapAutoDiscover(new ZendSoapWsdlComplexTypeStrategyArrayOfTypeSequence());

                    $auto->setClass($controllerClassName);
                    $auto->setUri(sprintf('%s://%s%s', ApplicationBootstrap::getServiceManager()->get('config')[APPLICATION_ENV]['webServer']['protocol'],
                                                     $this->request->getUri()->getHost() , $this->request->getUri()->getPath()));
                    $auto->setServiceName(ucfirst($this->request->getModuleName()) . ucfirst($this->request->getControllerName()));

                    header('Content-type: application/xml');

                    echo $auto->toXML();



                } elseif (count($this->request->getQuery()) == 0) {

                    $this->preDispatch();

                    $wsdl = sprintf('%s://%s%s?wsdl', ApplicationBootstrap::getServiceManager()->get('config')[APPLICATION_ENV]['webServer']['protocol'],
                                                     $this->request->getUri()->getHost() , $this->request->getUri()->getPath());

                    $soapServer = new ZendSoapServer($wsdl);
                    $soapServer->setClass($controllerClassName);
                    $soapServer->handle();
                }

/* code */

This is a fragment of the function signature of one of the classes that the autodiscover will generate the wsdl based on the annotations:

/**
 * Allows to search for a patient based on the patient id
 *
 * @param int $id
 * @return ViewModelsPatientViewModel
 * @throws ApplicationException
 */
protected function searchPatientById($id) {
 /* .... code */

This is the class ViewModelsPatientViewModel and ViewModelDiagnosisViewModel Notice here how i used the annotations to declare that a field conatins an array of a complextype, and then how that is translated as ArrayOfDiagnosisViewModel on the wsdl

    namespace ViewModels;

    class PatientViewModel {

        /**
         * @var int
         * */
        public $id;

        /**
         * @var string
         * */
        public $firstname;

        /**
         * @var string
         * */
        public $lastname;

        /**
         *** @var ViewModelsDiagnosisViewModel[]**
         * */
        public $diagnosis;

    }

class DiagnosisViewModel {

    /**
     * @var int
     */
    public $id;

    /**
     * @var string
     */
    public $name;

}

And this is the WSDL generated

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://soa.local/soap/Sample/Main" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" name="SampleMain" targetNamespace="http://soa.local/soap/Sample/Main">
    <types>
        <xsd:schema targetNamespace="http://soa.local/soap/Sample/Main">
            <xsd:complexType name="DiagnosisViewModel">
                <xsd:all>
                    <xsd:element name="id" type="xsd:int" nillable="true"/>
                    <xsd:element name="name" type="xsd:string" nillable="true"/>
                </xsd:all>
            </xsd:complexType>
            **<xsd:complexType name="ArrayOfDiagnosisViewModel">
                <xsd:sequence>
                    <xsd:element name="item" type="tns:DiagnosisViewModel" minOccurs="0" maxOccurs="unbounded"/>
                </xsd:sequence>
            </xsd:complexType>**
            <xsd:complexType name="PatientViewModel">
                <xsd:all>
                    <xsd:element name="id" type="xsd:int" nillable="true"/>
                    <xsd:element name="firstname" type="xsd:string" nillable="true"/>
                    <xsd:element name="lastname" type="xsd:string" nillable="true"/>
                    <xsd:element name="diagnosis" type="tns:ArrayOfDiagnosisViewModel" nillable="true"/>
                </xsd:all>
            </xsd:complexType>
        </xsd:schema>
    </types>
    <portType name="SampleMainPort">
        <operation name="searchPatientById">
            <documentation>Allows to search for a patient based on the patient id</documentation>
            <input message="tns:searchPatientByIdIn"/>
            <output message="tns:searchPatientByIdOut"/>
        </operation>
    </portType>
    <binding name="SampleMainBinding" type="tns:SampleMainPort">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="searchPatientById">
            <soap:operation soapAction="http://soa.local/soap/Sample/Main#searchPatientById"/>
            <input>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://soa.local/soap/Sample/Main"/>
            </input>
            <output>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://soa.local/soap/Sample/Main"/>
            </output>
        </operation>
    </binding>
    <service name="SampleMainService">
        <port name="SampleMainPort" binding="tns:SampleMainBinding">
            <soap:address location="http://soa.local/soap/Sample/Main"/>
        </port>
    </service>
    <message name="searchPatientByIdIn">
        <part name="id" type="xsd:int"/>
    </message>
    <message name="searchPatientByIdOut">
        <part name="return" type="tns:PatientViewModel"/>
    </message>
</definitions>

NOTICE THAT JUST BY CHANGING THE STRATEGY AND THE RIGHT DOCBLOCKS ANNOTATIONS YOU CAN ACHIEVE THAT.

HOPE THIS SNIPPETS CAN HELP YOU TO FIND A SOLUTION.

Tuesday, September 13, 2022
 
2

Ok, finally I found a solution! You can define a ValidationGroup which allows you to set the attributes you'd like to validate. The others are not validated:

$form->setValidationGroup('name', 'email', 'subject', 'message');
$form->setData($data);
if ($form->isValid()) {
    ...
Friday, November 4, 2022
2

Don't know if it will help, but instead of prefix you can wrap elements in form or fieldset with form/fieldset name.

You just need to have a name of form or set it and then use setWrapElements

$form->setName('some_name');
$form->setWrapElements(true);
$form->prepare();

from this point full name of element, for example 'password' will be "some_name['password']"

If you are using annotations you can use this with combination of ComposedObject. It's very good explained here: http://devblog.x2k.co.uk/using-the-composedobject-zend-framework-2-form-annotation/

Martin

Tuesday, December 13, 2022
 
2

Insert [/] to fix it. try:

'route' => '/admin[/:controller[/:action]][/]',
Saturday, December 3, 2022
 
3

FAQ - (Answers based on personal experiment done yesterday)

What has changed in Zend Framework 2 from Zend Framework 1?

Architecture

ZF1 is based on MVC , ZF2 is based on MOVE. Huge difference. MOVE = Model Operations Views Events , MVC = Models Views Controllers. More here. Zend Framework 2 uses 100% object-oriented code and utilises most of the new features of PHP 5.3, namely namespaces, late static binding, lambda functions and closures. source

Size of installation

The latest ZF1 file is approx 30Mb and ZF2 is approx 2.5Mb (Zipped).

Dependency

ZF1 is core set of libraries and very loosely coupled architecture (with respect to its competitor/player - CakePHP). ZF1 does not require much of 'gems' (as in ruby) but, can do better with plugins. ZF2 requires you to know about composer - phar and soon it may out-match any other framework. New concept : Dependency Injection for Zend fans.

Certification

Certification is available only for ZF1, however, there are rumours about their talks for ZF2 certs though training material is available online.

Conventions

classname in ZF1 was Zend_Db_Table for class in Zend/Db/Table.php whereas in ZF2, it is class MyAuthAdapter . Enough said.

Community

ZF1 was backed by Zend Technologies (and few other, unnamed). ZF2 has remarkable supporters including Google and Microsoft. Source here

Speed

It took approx 20 times more time to execute "Hello World!" in ZF2. I am not judging here. I could be wrong here. DIY.

Which one should I opt for?

MVC is been around since almost a decade and if you are one of them who are feeling sad for a new architecture altogether then hey! IT is 'your chosen' domain, keep up with the trends and update yourself! Start ZF2 from here.

Thursday, November 24, 2022
 
b_f
 
b_f
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :