goetas-webservices/soap-client


README

Build Status

PHP 实现SOAP 1.1和1.2客户端规范。

优点

  • 纯PHP,不依赖ext-soap
  • 可扩展的(支持JMS事件监听器)
  • PSR-7 HTTP消息
  • PSR-17 HTTP消息工厂
  • PSR-18 HTTP客户端
  • 生产环境不解析WSDL/XSD
  • IDE类型提示支持

仅支持document/literal样式,且webservice应遵循WS-I指南。

没有计划支持废弃的rpc和encoded样式。不遵循WS-I规范的webservice可能工作,但官方不支持。

演示

goetas-webservices/soap-client-demo是一个演示项目,展示了如何在通用的PHP web应用程序中消费SOAP API。

安装

安装goetas-webservices / soap-client的推荐方法是使用Composer

将此包添加到您的composer.json文件中。

{
    "require": {
        "goetas-webservices/soap-client": "^0.3",
    },
    "require-dev": {
        "goetas-webservices/wsdl2php": "^0.5.1",
    },
}

如何使用

为了提高性能,此库基于所有SOAP/WSDL元数据必须编译成PHP兼容元数据(实际上是一个大型的普通PHP数组,因此速度非常快)的概念。

为此,我们必须定义一个配置文件(在本例中称为config.yml),其中包含一些重要信息。

以下是一个示例

# config.yml

soap_client:
  alternative_endpoints:
    MyServiceName:
      MySoapPortName: http://localhost:8080/service

  namespaces:
    'http://www.example.org/test/': 'TestNs/MyApp'
  destinations_php:
    'TestNs/MyApp': soap/src
  destinations_jms:
    'TestNs/MyApp': soap/metadata
  aliases:
    'http://www.example.org/test/':
      MyCustomXSDType:  'MyCustomMappedPHPType'

  metadata:
    'test.wsdl': ~
    'http://www.webservicex.net/weather.asmx?WSDL': ~

此文件包含一些重要部分

SOAP特定

  • alternative_endpoints(可选)允许您指定在开发集成时可以使用的替代URL。如果此参数不存在,将使用WSDL文件中定义的URL,但如果设置了,将使用为名为MyServiceName的服务和MySoapPortName端口指定的URL。

  • unwrap_returns(可选,默认:false)允许定义“包装”SOAP服务的模式。指示客户端“解包”所有返回值。

WSDL特定

  • metadata指定放置用于生成所有所需PHP元数据的WSDL文件的位置。

XML/XSD特定

  • namespaces(必需)定义XML命名空间和PHP命名空间之间的映射。(在示例中,我们具有将http://www.example.org/test/ XML命名空间映射到TestNs\MyApp

  • destinations_php(必需)指定保存属于TestNs\MyApp PHP命名空间的PHP类的目录。(在本例中,TestNs\MyApp类将保存在soap/src目录中。)

  • destinations_jms(必需)指定保存属于TestNs\MyApp PHP命名空间的JMS序列化器元数据文件的目录。(在本例中,TestNs\MyApp元数据将保存在soap/metadata目录中。)

  • aliases(可选)指定由自定义JMS序列化器处理程序处理的映射。允许指定不生成某些XML类型的元数据,并直接分配给PHP类。为此PHP类需要创建一个自定义JMS序列化/反序列化处理程序。

元数据生成

为了能够使用SOAP客户端,我们必须生成一些元数据和PHP类。

要这样做,我们可以运行

bin/soap-client generate \
 tests/config.yml \
 --dest-class=GlobalWeather/Container/SoapClientContainer \
 soap/src-gw/Container 
  • bin/soap-client generate是我们正在运行的命令
  • tests/config.yml是我们配置文件的路径
  • --dest-class=GlobalWeather/Container/SoapClientContainer 允许指定包含所有 Web 服务元数据的容器的完全限定类名。
  • soap/src/Container 是保存包含所有 Web 服务元数据的容器类的路径(您需要配置自动加载器来加载它)

使用客户端

一旦所有元数据都生成,我们就可以使用我们的 SOAP 客户端。

让我们看看一个最小示例

// composer auto loader
require __DIR__ . '/vendor/autoload.php';

// instantiate the main container class
// the name was defined by --dest-class=GlobalWeather/Container/SoapClientContainer
// parameter during the generation process
$container = new SoapClientContainer();

// create a JMS serializer instance
$serializer = SoapContainerBuilder::createSerializerBuilderFromContainer($container)->build();
// get the metadata from the container
$metadata = $container->get('goetas_webservices.soap.metadata_reader');

$factory = new ClientFactory($metadata, $serializer);

/**
 * @var $client \GlobalWeather\SoapStubs\WeatherSoap
 */
 // get the soap client
$client = $factory->getClient('http://www.webservicex.net/weather.asmx?WSDL');

// call the webservice
$result = $client->getWeather(2010, "May", "USA");

// call the webservice with custom headers
$result = $client->getWeather(2010, "May", "USA", Header::asMustUnderstand(new SomeAuth('me', 'pwd')));

请注意 @var $client \GlobalWeather\SoapStubs\WeatherSoap。生成的元数据还有一个“存根”类,它允许现代 IDE 为参数和返回数据提供类型提示。

这使得您能够更快地开发客户端。

使用具有动态端点的客户端

假设您有具有不同端点(例如,针对每个客户)的相同 Web 服务,因此您想动态更改端点,而无需在配置中为每个客户编写新的端点并运行生成器。

借助 Symfony 的 EnvVarProcessorInterface,您可以使用 alternative_endpoints 动态设置 Web 服务端点。

以下是一个示例

# config.yml
soap_client:
  alternative_endpoints:
    MyServiceName:
      MySoapPortName: 'env(custom_vars:ENDPOINT_SERVICE1_PORT1)'

因此,SoapClientContainer 将在运行时解析特定服务和端点的端点,并将值从 ENDPOINT_SERVICE1_PORT1 变量中获取。

以下是一个简单的类,该类实现 EnvVarProcessorInterface,负责为我们自定义端点位置提供值(如 custom_vars:ENDPOINT_SERVICE1_PORT1)。

// SimpleEnvVarProcessor.php used for the `env(custom_vars:*)` variables resolution

use Symfony\Component\DependencyInjection\EnvVarProcessorInterface;

class SimpleEnvVarProcessor implements EnvVarProcessorInterface
{
    private $map = [];

    public function __construct(array $map)
    {
        $this->map = $map;
    }

    public function getEnv($prefix, $name, \Closure $getEnv)
    {
        return $this->map[$name];
    }

    public static function getProvidedTypes()
    {
        return [];
    }
}

最后,使用 SoapClientContainer

// instantiate our variable processor and set the values for our custom variables
$varProcessor = new SimpleEnvVarProcessor([
    'ENDPOINT_SERVICE1_PORT1' => 'http://localhost:8080/service'
]);

// create an empty symfony container and set into it the $varProcessor namined as 'custom_vars'
$varContainer = new \Symfony\Component\DependencyInjection\Container(); 
$varContainer->set('custom_vars', $varProcessor);

// create the soap container and use $varContainer "env()" style variables resolution
$container = new SoapClientContainer();
$container->set('container.env_var_processors_locator', $varContainer);

// now $container can be used as explained in the section "Using the client"

这样,即使 WSDL 表示的是其他内容,MyServiceName.MySoapPortName 的端点也将动态解析为 http://localhost:8080/service

注意

本项目的代码遵循 MIT 许可。如需专业支持,请联系 goetas@gmail.com 或访问 https://www.goetas.com