SOAP Headers

Are SOAP headers supported both in API and in WSDL generator? I didn`t find any indications. Are these planned?

That’s really good question. Do you plan implementing soap header support. It will really make Yii preferred for more complex solutions !

I have quite a big project at my desk and these headers are stopping me.

I think a lot of people would like to know about this. Please respond :)

I’ll have to use C#.NET otherwise :(

I’m using a derived class of the WsdlGenerator like this:




<?php


class WsdlGenerator extends CWsdlGenerator {


	/**

	 * Generates the WSDL for the given class.

	 * @param string class name

	 * @param string Web service URL

	 * @param string encoding of the WSDL. Defaults to 'UTF-8'.

	 * @return string the generated WSDL

	 */

	public function generateWsdl($className, $serviceUrl, $encoding='UTF-8')

	{

		$ret = parent::generateWsdl($className, $serviceUrl, $encoding);


		$doc = DOMDocument::loadXML($ret);


		$xp = new DOMXPath($doc);

		

		$headerMessage = $doc->createElement('wsdl:message');

		$headerMessage->setAttribute('name', 'ApiKeyHeader');

		$messagePart = $doc->createElement('wsdl:part');

		$messagePart->setAttribute('name','apiKeyHeader');

		$messagePart->setAttribute('type','tns:ApiKeyHeader');

		$headerMessage->appendChild($messagePart);




		$doc->firstChild->appendChild($headerMessage);


		$headerType = $doc->createElement('xsd:complexType');

		$headerType->setAttribute('name', 'ApiKeyHeader');

		$headerType->appendChild($all = $doc->createElement('xsd:all'));

		$element = $doc->createElement('xsd:element');

		$element->setAttribute('name', 'key');

		$element->setAttribute('type', 'xsd:string');

		$all->appendChild($element);


		

		$element = $xp->query('/wsdl:definitions/wsdl:types/xsd:schema')->item(0);

		if (!$element) {

			$element = $doc->createElement('xsd:schema');

			$types=$doc->createElement('wsdl:types');

			$element->setAttribute('targetNamespace',"urn:{$className}wsdl");

			$types->appendChild($element);

			$doc->documentElement->appendChild($types);

		}

		$element->appendChild($headerType);


		$list = $xp->query('/wsdl:definitions/wsdl:binding/wsdl:operation/wsdl:input');

		for($i = 0; $i < $list->length; $i++) {

			$e = $list->item($i);

			$soapHeader = $doc->createElement('soap:header');

			$soapHeader->setAttribute('message', 'tns:ApiKeyHeader');

			$soapHeader->setAttribute('use', 'encoded');

			$soapHeader->setAttribute('part', 'apiKeyHeader');

			$soapHeader->setAttribute('namespace', $e->firstChild->getAttribute('namespace'));

			$soapHeader->setAttribute('encodingStyle', $e->firstChild->getAttribute('encodingStyle'));


			$e->appendChild($soapHeader);

		}


		return $doc->saveXML();


	}




}



Sadly, all the methods of the original implementation are private so you can’t override them :( If you want to do simple stuff like adding more types, you have to copy the whole file…

Thanx for the code. I send the headers always(even they are not present in the WSDL). So my problem is how can i read them at the server side.

Right now i’m implementing my own base controller which handles beforeWebMethod(), “extracts” headers in array and saves them in local var for use in the functions later.

When i’m ready i’ll paste some code here :)

Here is my implementation that reads the soap headers of incoming soap requests. I dont pretend to be perfect but it works for me.


    

class WebServiceController extends Controller implements IWebServiceProvider

{

    public $rawPOST; //Contains the RAW unparsed XML

    public $SOAP_HEADERS; //Contains SOAP HEADERS as array Header=>array(param=>value)

    public $HEADER_NS = 'Namespace'; //the headers namespace


    public function beforeWebMethod($service)

    {

        $this->rawPOST = file_get_contents('php://input');


        $xml = simplexml_load_string($this->rawPOST);

        $headers = $xml->xpath('//SOAP-ENV:Header');

        foreach($headers as $header)

        {

           $items = $header->xpath('//'.$this->HEADER_NS.':*');

           foreach($items as $value)

                $this->SOAP_HEADERS[$value->getName()] = (array)$value;

        }        

        //if there is a AuthHeader then login user

        if(Yii::app()->user->isGuest and $this->SOAP_HEADERS['TAuthHeader'])

        {

            $identity=new UserIdentity($this->SOAP_HEADERS['TAuthHeader']['UserName'], 

                $this->SOAP_HEADERS['TAuthHeader']['Password']);

            $identity->authenticate();            

            if($identity->errorCode == UserIdentity::ERROR_NONE)

                Yii::app()->user->login($identity,$duration);             

        }

        return true;

    }

}

My controllers(with services) extend from this base class.

Hi, this is an old thread, but…

I need to use SOAP Headers, in my webservice. I added header into my client, but in web service there is no such element (i dont know how to add this to wsdl)

And i got this error:


<faultcode>CException</faultcode><faultstring>WsController and its behaviors do not have a method or closure named "AuthHeader". 

Can anybody help?