使用 SOAP API
SOAP(简单访问对象协议)是基于 XML 的,就像 XML-RPC 一样,是祖先,文件名为 WSDL ,用于描述要公开的方法。
该协议通常基于 SOAP-Enveloppe , SOAP-Body 和 SOAP-Header ,数据被包含在一个结构中,并被解释为来自不同语言的相同方式。
有关更多信息,请参阅: wiki 上的 SOAP
如上所述,描述 Web 服务最重要的是 WSDL 文件,请参阅: wiki 上的 WSDL 说明
这项工作的基础是定义 SOAP API 上公开的内容,你的类和业务流程将由基本的 PHP SOAPServer 类自动处理。你还需要代码!
让我们看看文件是如何构造的:
- 服务:设置 API URI 以及将关联的内容。
- 绑定:它定义与服务关联的操作
- 操作:你希望向 Web 公开的一些方法
- PortTypes:定义查询和响应
- 请求和响应:你期望输入和输出
- 消息:你对每个 IO 的期望(参数)形式,它们可以是简单的(字符串,整数,浮点…)或复杂类型(结构化格式)
有了这些基本信息,你就可以实现所需的所有 API。
想象一下,你想要创建一个 SOAP api 来管理本地数据库上的 StackOverFlower(User)
。
让我们举个例子吧!
安装 Web 服务器,Php cli,Composer,Symfony 2.8,创建一个新的 BundleExampleBundle
并构建如上所述的模式。
在我们开始构建业务逻辑之前,我们必须知道控制器的公开内容。这项工作是通过使用 WSDL 完成的。这是一个很好的 WSDL 语法示例:
<definitions name="StackOverFlowerService"
targetNamespace="http://example/soap/stackoverflower.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://example/soap/stackoverflower.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="NewRequest">
<part name="name" type="xsd:string"/>
</message>
<message name="NewResponse">
<part name="status" type="xsd:string"/>
</message>
<message name="getListRequest"></message>
<message name="getListResponse">
<part name="list" type="xsd:string"/>
</message>
<message name="editRequest">
<part name="id" type="xsd:string"/>
<part name="name" type="xsd:string"/>
</message>
<message name="editResponse">
<part name="status" type="xsd:string"/>
</message>
<message name="deleteRequest">
<part name="id" type="xsd:string"/>
</message>
<message name="deleteResponse">
<part name="status" type="xsd:string"/>
</message>
<portType name="StackOverFlower_PortType">
<operation name="newStack">
<input message="tns:NewRequest"/>
<output message="tns:NewResponse"/>
</operation>
<operation name="getList">
<input message="tns:getListRequest"/>
<output message="tns:getListResponse"/>
</operation>
<operation name="edit">
<input message="tns:editRequest"/>
<output message="tns:editResponse"/>
</operation>
<operation name="delete">
<input message="tns:deleteRequest"/>
<output message="tns:deleteResponse"/>
</operation>
</portType>
<binding name="StackOverFlower_Binding" type="tns:StackOverFlower_PortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="newStack">
<soap:operation soapAction="newStack"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:new"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:new"
use="encoded"/>
</output>
</operation>
<operation name="getList">
<soap:operation soapAction="getList"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:get-list"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:get-list"
use="encoded"/>
</output>
</operation>
<operation name="edit">
<soap:operation soapAction="edit"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:edit"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:edit"
use="encoded"/>
</output>
</operation>
<operation name="delete">
<soap:operation soapAction="delete"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:delete"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:example:delete"
use="encoded"/>
</output>
</operation>
</binding>
<service name="StackOverFlower_Service">
<documentation>Description File of StackOverFlowerService</documentation>
<port binding="tns:StackOverFlower_Binding" name="StackOverFlower_Port">
<soap:address
location="http://example/stackoverflower/" />
</port>
</service>
</definitions>
我们必须在你的 web symfony 目录中(在 soap 子目录中,并将其命名为“stackoverflower.wsdl”)。
从 WSDl 示例中获得灵感。你可以使用 Online WSDl Validator 对其进行验证
在此之后,我们可以从 SOAP Symfony 2.8 Doc 启发我们的基本服务和控制器。
服务,由 PHP SOAPServer 处理:
#src\ExampleBundle\Services\StackOverFlowerService.php
namespace ExampleBundle\Services;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use ExampleBundle\Entity\StackOverFlower;
class StackOverFlowerService
{
private $em;
private $stackoverflower;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function newStack($name)
{
$stackoverflower = new StackOverFlower();
$stackoverflower->setName($name);
$this->em->persist($stackoverflower);
$this->em->flush();
return "ok";
}
public function getList()
{
$stackoverflowers = $this->em->getRepository("ExampleBundle:StackOverFlower")->findAll();
$encoders = array(new XmlEncoder(), new JsonEncoder());
$normalizers = array(new ObjectNormalizer());
$serializer = new Serializer($normalizers, $encoders);
return $serializer->serialize($stackoverflowers, 'json');
}
public function edit($id, $name)
{
$stackoverflower = $this->em->getRepository("ExampleBundle:StackOverFlower")->findOneById($id);
$stackoverflower->setName($name);
$this->em->persist($stackoverflower);
$this->em->flush();
return "ok";
}
public function delete($id)
{
$stackoverflower = $this->em->getRepository("ExampleBundle:StackOverFlower")->findOneById($id);
$this->em->remove($stackoverflower);
$this->em->flush();
return "ok";
}
}
配置此服务:
#src\ExampleBundle\Resources\config\services.yml
services:
stackoverflower_service:
class: ExampleBundle\Services\StackOverFlowerService
arguments: [@doctrine.orm.entity_manager]
如你所见,我们将 Doctrine Entity Manger 注入依赖项,因为我们必须将它用于 CRUD StackOverFlower 对象。
控制器,公开服务对象:
#src\ExampleBundle\Controller\StackOverFlowerController.php
namespace ExampleBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class StackOverFlowerController extends Controller
{
public function indexAction()
{
ini_set("soap.wsdl_cache_enabled", "0");
$options = array(
'uri' => 'http://example/app_dev.php/soap',
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true
);
$server = new \SoapServer(dirname(__FILE__).'/../../../**web/soap/stackoverflower.wsdl**', $options);
$server->setObject($this->get('stackoverflower_service'));
$response = new Response();
$response->headers->set('Content-Type', 'text/xml; charset=utf-8');
ob_start();
$server->handle();
$response->setContent(ob_get_clean());
return $response;
}
}
要了解有关服务的更多信息,请参阅: Symfony doc 上的服务容器
路线 :
example_soap:
path: /soap
defaults: { _controller: ExampleBundle:StackOverFlower:index }
基本的 Twig 模板:
#src\ExampleBundle\Resources\views\Soap\default.html.twig
{% if status is defined %}
{{ status }}
{% else %}
{{ list }}
{% endif %}
我们用 Symfony 2.8 创建了第一个 SOAP API!
在你暴露它之前,我们必须测试!!
在 StackOverFlowerController 中,添加:
public function testNewAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->newStack($request->query->get('name'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('status' => $result));
}
public function testEditAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->edit($request->query->get('id'), $request->query->get('name'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('status' => $result));
}
public function testGetListAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->getList();
return $this->render('ExampleBundle:Soap:default.html.twig', array('list' => $result));
}
public function testDeleteAction(Request $request)
{
$service = $this->get('stackoverflower_service');
$result = $service->delete($request->query->get('id'));
return $this->render('ExampleBundle:Soap:default.html.twig', array('list' => $result));
}
// To test this from an another server, you can type this :
// $client = new \SoapClient("http://example/app_dev.php/soap?wsdl", array("trace" => 1, "exception" => 1));
// $result = $client->newStack($request->query->get('name'));
// print_r($result);
路线:
test_new:
path: /stackoverflower/new
defaults: { _controller: ExampleBundle:StackOverFlower:testNew }
test_edit:
path: /stackoverflower/edit
defaults: { _controller: ExampleBundle:StackOverFlower:testEdit }
test_get_list:
path: /stackoverflower/get-list
defaults: { _controller: ExampleBundle:StackOverFlower:testGetList }
test_delete:
path: /stackoverflower/delete
defaults: { _controller: ExampleBundle:StackOverFlower:testDelete }
你可以在浏览器中输入:
这是使用 SOAP 的非安全 API 的一个非常基本的示例,我可以稍后在 api 密钥身份验证后面做一个安全示例的示例。
所有人……
马蒂厄