View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
Zend_Service_Server
{zone-data}

{zone-data:proposer-list}
[Davey Shafik|mailto:davey@php.net]
{zone-data}

{zone-data:revision}
1.0 - 1 August 2006: Intial Proposal.
{zone-data}

{zone-data:overview}
An automated SOAP/XML-RPC/REST server that will
expose any code using any of the above protocols.
Zend_Service_Server will also generate
human-readable documentation.
{zone-data}

{zone-data:references}
Initial idea is based on my original efforts on
WSDL generation for Cerebral Cortex. It has since
come to my attention, there is also (again, SOAP
specific) PEAR's Net_Service.

* [Crtx_SOAP_AutoDiscover|http://crtx.org/index.php?page=CrtxSoapAutoDiscover]
* [PEAR::Service_Webservice|http://pear.php.net/package/Services_Webservice/]
{zone-data}

{zone-data:requirements}
Must allow the user to expose any class with no
special requirements placed on the author. The
only exception to this is that all methods must
return values, they cannot simply output them.

All servers must provide a SoapServer-like interface
allowing for instantiation outside of this automated
process and registering of both single class and
multiple functions. They _should_ also provide a way to
generate documentation specific to the implementation.
{zone-data}

{zone-data:dependencies}
* Zend_Uri
* Zend_XmlRpc_Server (not yet created)
* Zend_Service_Exception
{zone-data}

{zone-data:operation}
Zend_Service_Server will require that a file
containing a class be given as the constructor
argument. This is required because the tokenizer
extension is used for PHP 5.0.x compatibility
(though, I forget the /exact/ problem with
ext/reflection that prompted this decision).

The operation from here depends on the GET arguments.

The operations allowed are as follows:

?wsdl = WSDL Generation
?soap = SOAP Server (using ext/soap's SoapServer)
?rest = REST Server (using Zend_Service_Server_Rest)
?rpc = XML-RPC Server (using Zend_XmlRpc_Server)

Passing no argument will output user-readable documentation,
detailing the methods exposed. If you supply one of the
above *and* the 'docs' argument, it will output
implementation specific documentation, and possibly
allow for submission of requests using a form (a la
.NET)
{zone-data}

{zone-data:class-list}
* Zend_Service_Server - Class that handles user request and
forwards request to implementation specific server

* Zend_Service_Server_Interface - Interface that all (except
ext/soap) must implement to be accepted as backends.

* Zend_Service_Server_Rest - REST server; this will either create
a nice markup based on reflection, or will allow
the user to return SimpleXML, DomDocument or DomNode objects.

* Zend_Service_Server_Soap_WsdlCreator - Generates WSDL files for
classes automatically.

* Zend_Service_Server_Wsdl - WSDL Toolkit for creating WSDL
files (not automated)

* Zend_Service_Server_Wsdl_Parser - WSDL Parser

* Zend_Service_Server_Wsdl_Parser_Result - WSDL Parser Result
container

* Zend_Service_Server_Wsdl_CodeGenerator - WSDL -> PHP Skeleton
creator

In addition to these, there will be the documentation creators:

* Zend_Service_Server_Documentor

* Zend_Service_Server_Documentor_REST

* Zend_Service_Server_Documentor_XmlRpc

* Zend_Service_Server_Documentor_Soap

Furthermore, depending on the implementation of Zend_XmlRpc_Server
there may be a requirement to wrap it with a Zend_Service_Server_XmlRpc
class to make it conform to the Zend_Service_Server_Interface API.

Finally, there will need to be a REST client class, whether this is
implemented within Zend_Service_Rest or as another entity is undecided.
{zone-data}

{zone-data:use-cases}
The ultimate use-case for this is anybody wishing to provide
webservices to their users and not wanting to be tied to a specific
technology (i.e. SOAP). It also allows for additional backends to be
plugged in at will for custom formats.

h2. Front facing file
{code}
<?php
require_once 'Zend/Service/Server.php';

$server = new Zend_Service_Server('./testClass.php');

$server->handle();
?>
{code}

h2. testClass.php
{code}
<?php
class TestClass {
/**
* Class Constructor
*/
public function __construct()
{
// Some Constructor
}

/**
* Say Hello to Somebody
*
* @return string
*/
public function sayHello($who, $when)
{
return "Hello $who, Good $when";
}

/**
* Something to return an array
*
* @return array
*/
public function returnArray()
{
return array("foo" => "bar", "baz" => "bat");
}


private function doSomething()
{
// Some Private Method
}
}
?>
{code}

h2. Example Exchanges

h3. Request
{code}
?rest&method=SayHello&wHo=Davey&WHEN=Day
{code}

h3. Response
{code:xml}
<TestClass>
<sayHello>
<response>
Hello World, Good Day
</response>
<status>
success
</status>
</sayHello>
</TestClass>
{code}

h3. Request
{code}
?rest&method=returnArray
{code}

h3. Response
{code:xml}
<TestClass>
<returnArray>
<foo>bar</foo>
<baz>bat</baz>
<status>success</status>
</returnArray>
</TestClass>
{code}

h3. Request
{code}
?wsdl
{code}

h3. Response
{code:xml}
<?xml version="1.0"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://example.org/Zend/Services/example.php?soap"
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/"
name="TestClass"
targetNamespace="http://example.org/tests/Zend/Services/example.php?soap">

<documentation>Zend_Service_Server Test Class</documentation>
<portType name="TestClassPort">
<operation name="sayHello">
<input message="tns:sayHelloRequest" />
<output message="tns:sayHelloResponse" />
</operation>
<operation name="returnArray">

<input message="tns:returnArrayRequest" />
<output message="tns:returnArrayResponse" />
</operation>
</portType>
<binding name="TestClassBinding" type="tns:TestClassPort">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="sayHello">
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />

</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
<soap:operation soapAction="http://example.org/Zend/Services/example.php?soap#sayHello" />
</operation>
<operation name="returnArray">
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />

</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</output>
<soap:operation soapAction="http://example.org/Zend/Services/example.php?soap#returnArray" />
</operation>
</binding>
<service name="TestClassService">
<port name="tns:TestClassPort" binding="tns:TestClassBinding">

<soap:address location="http://example.org/Zend/Services/example.php?soap" />
</port>
</service>
<message name="sayHelloRequest">
<part name="longdesc" type="xsd:anyType" />
<documentation>Say Hello to Somebody</documentation>
</message>
<message name="sayHelloResponse">

<part name="sayHelloReturn" type="xsd:string" />
</message>
<message name="returnArrayRequest">
<part name="longdesc" type="xsd:anyType" />
<documentation>Something to return an array</documentation>
</message>
<message name="returnArrayResponse">
<part name="returnArrayReturn" type="soap-enc:Array" />

</message>
</definitions>
{code}

{zone-data}

{zone-data:skeletons}
{code}
class Zend_Service_Server {
public function __construct() { }

public function handle() { }
}
{code}

{code}
interface Zend_Service_Server_Interface {
public function addFunction($funcname);

public function getFunctions();

public function handle();

public function setClass($class);
}
{code}

{code}
class Zend_Service_Rest implements Zend_Service_Server_Interface { }
{code}

{code}
class Zend_Service_Server_Wsdl {
public function __construct() { }

public function addBinding() { }

public function addBindingOperation() { }

public function addDocumentation() { }

public function addMessage() { }

public function addPortOperation() { }

public function addPortType() { }

public function addService() { }

public function addSoapBinding() { }

public function addSoapOperation() { }

public function addTypes() { }

public function dump() { }

public function toDomDocument() { }

public function toXML() { }
}
{code}

{code}
class Zend_Service_Server_Wsdl_Parser {
static public function getDocs() { }

static public function getOperationInputs() { }

static public function getOperationOutput() { }

static public function parse() { }
}
// The static-ness of this class is left over from its previous implementation in
// Cerebral Cortex and could be removed quite easily.
{code}

{code}
class Zend_Service_Server_Wsdl_Parser_Result { }
// Contains on named properties for accessing parser results
{code}

{code}
class Zend_Service_Server_Wsdl_CodeGenerator {
static public function parse($wsdl, $output_file = null) { }

static private generatorPhp() { }
}
{code}

{code}
class Zend_Service_Server_Soap_WsdlCreator {
public function __construct($code_file, $service_uri, $output_file = null, $ignore_methods = array()) { }

public function createWsdl() { }

static public function getType() { }

private function saveToFile() { } // Should be made public and $output_file removed from constructor...

public function toXML() { }
}
{code}

Documentation classes are seen as specialized HTML responding servers.

{code}
class Zend_Service_Server_Documentor implements Zend_Service_Server_Interface { }
{code}

{code}
class Zend_Service_Server_Documentor_Rest extends Zend_Service_Server_Documentor { }
{code}

{code}
class Zend_Service_Server_Documentor_Soap extends Zend_Service_Server_Documentor { }
{code}

{code}
class Zend_Service_Server_Documentor_XmlRpc extends Zend_Service_Server_Documentor { }
{code}

ToDo:

REST client that works with Zend_Service_Server_Rest automatically.
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>