信息化 频道

如何用Zend Framework实现SOAP服务?

 第 2 步:初始化应用数据库和模型

  下一步是初始化应用数据库。所以,我们要创建一个新的MySQL表来保存产品信息,如下所示:

  以下是引用片段:
  mysql> CREATE TABLE IF NOT EXISTS products (
  ->   id int(11) NOT NULL AUTO_INCREMENT, 
  ->   title varchar(200) NOT NULL,
  ->   shortdesc text NOT NULL,
  ->   price float NOT NULL,
  ->   quantity int(11) NOT NULL,
  ->   PRIMARY KEY (id)
  -> ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


  在这个表中填入一些示例记录以便开始开发,如下所示:

  以下是引用片段:
  mysql> INSERT INTO products (id, title, shortdesc, price, quantity) VALUES(1, 
  ->  'Ride Along Fire Engine', 'This red fire engine is ideal for toddlers who 
  ->  want  to travel independently. Comes with flashing lights and beeping horn.', 
  ->  69.99, 11);
  Query OK, 1 row affected (0.08 sec)
  mysql> INSERT INTO products (id, title, shortdesc, price, quantity) VALUES(2, 
  -> 'Wind-Up Crocodile Bath Toy', 'This wind-up toy is the perfect companion  
  -> for hours of bathtub fun.', 7.99, 67);
  Query OK, 1 row affected (0.08 sec)


  第 3 步:配置应用的名称空间

  最后一步是为Zend Framework自动加载配置名称空间。这个步骤将在需要时实现自动加载特定应用类到应用中。在这里,我假设应用的名称空间为Example,而特定应用类(如SOAP服务类)将存储在$PROJECT/library/Example/中。所以,要修改应用配置文件$PROJECT/application/configs/application.ini并添加下面一行到文件中:

  以下是引用片段:
  autoloaderNamespaces[] = "Example_"


  您现在已经完成了创建一个SOAP服务的所有准备工作!

  查询数据

  因为这是一个示例应用,我将尽量保持简单,并只在默认模块的IndexController上创建一个处理SOAP请求的动作;然而,在实际中,您可能希望使用一个单独的控制器处理SOAP请求。编辑文件$PROJECT/application/controllers/IndexController.php,然后添加新的动作,如 清单 3 所示:

  清单 3. soapAction() 的定义   

  以下是引用片段:
  <?php
  class IndexController extends Zend_Controller_Action
  {
  public function soapAction()
  {
  // disable layouts and renderers
  $this->getHelper('viewRenderer')->setNoRender(true);

  // initialize server and set URI
  $server = new Zend_Soap_Server(null, 
  array('uri' => 'http://example.localhost/index/soap'));
  // set SOAP service class
  $server->setClass('Example_Manager');
  // handle request
  $server->handle();
  }
  }


  清单 3 传递一个null值到对象构造函数的第一个参数,以非WSDL模式初始化了一个新的Zend_Soap_Server对象。如果以非WSDL模式创建服务器,我们必须指定服务器URI;在 清单 3 中,这是在作为第二个参数传递给构造函数的选项数组中指定的。

  接下来,服务器对象的setClass()函数用于将一个服务类附加到服务器上。这个类实现了SOAP服务的可用函数;这个服务器将在SOAP请求的响应中自动调用这些函数。如果您喜欢,您也可以使用addFunction()和loadFunctions()函数将用户自定义函数附加到服务器上,而不需要使用 setClass()函数附加整个类。

  正如之前所提到的,Zend_Soap_Server类并没有提供它自己的SOAP服务器实现;它只是封装了 PHP 的内置SOAP扩展。因此,一旦所有先决条件都准备好后,清单 3 中的handle()函数会负责初始化内置的PHP SoapServer对象,将它传递给请求对象,并调用该对象的handle() 函数处理SOAP请求。

  虽然所有这些都做好了,但是这还远远不够,因为服务类还没有定义。接下来我们使用 清单 4 中的代码创建这个类定义,将创建的类定义保存到 $PROJECT/library/Example/Manager.php:

  清单 4. 带有get*()函数的服务对象定义   

  以下是引用片段:
  <?php
  class Example_Manager {
  /**
  * Returns list of all products in database
  *
  * @return array
  */
  public function getProducts() 
  {
  $db = Zend_Registry::get('Zend_Db');        
  $sql = "SELECT * FROM products";      
  return $db->fetchAll($sql);      
  }
  /**
  * Returns specified product in database
  *
  * @param integer $id
  * @return array|Exception
  */
  public function getProduct($id) 
  {
  if (!Zend_Validate::is($id, 'Int')) {
  throw new Example_Exception('Invalid input');          
  }
  $db = Zend_Registry::get('Zend_Db');        
  $sql = "SELECT * FROM products WHERE id = '$id'";   
  $result = $db->fetchAll($sql);      
  if (count($result) != 1) {        
  throw new Exception('Invalid product ID: ' . $id);  
  } 
  return $result;  
  }
  }
  ?>


  清单 4 创建了一个单独的服务类,它包含两个函数。getProducts()函数使用Zend_Db查询表中所有的产品记录,然后将它们作为一个数组返回,而 getProduct() 函数则接收一个产品标识符,然后只返回特定的一条记录。然后SOAP服务器将这个方法的返回值转换成一个 SOAP 响应数据包,并将它返回给发送请求的客户端。清单8包含一个响应数据包的例子:

  如果您还在疑惑Zend_Db是在哪里初始化的,我可以告诉您它是在应用启动加载器中初始化的,即$PROJECT/application/Bootstrap.php。这个 Bootstrap.php包含了一个 _initDatabase()函数,它创建Zend_Db适配器,并将它注册到应用注册表中。清单 5 显示这部分代码:

  清单 5. 数据库适配器初始化

  以下是引用片段:
  <?php
  class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
  {
  protected function _initDatabase()
  {
  $db = new Zend_Db_Adapter_Pdo_Mysql(array(
  'host'     => 'localhost',
  'username' => 'user',
  'password' => 'pass',
  'dbname'   => 'example'
  ));
  Zend_Registry::set('Zend_Db', $db); 
  }
  }

  为了看到实际结果,要创建一个SOAP客户端(清单 6),然后使用它连接SOAP服务,并请求getProducts()函数。

  清单 6. 一个示例SOAP客户端

  以下是引用片段:
  <?php
  // load Zend libraries
  require_once 'Zend/Loader.php';
  Zend_Loader::loadClass('Zend_Soap_Client');
  // initialize SOAP client
  $options = array(
  'location' => 'http://example.localhost/index/soap',
  'uri'      => 'http://example.localhost/index/soap'
  );
  try {
  $client = new Zend_Soap_Client(null, $options);  
  $result = $client->getProducts();
  print_r($result);
  } catch (SoapFault $s) {
  die('ERROR: [' . $s->faultcode . '] ' . $s->faultstring);
  } catch (Exception $e) {
  die('ERROR: ' . $e->getMessage());
  }
  ?>


  SOAP客户端将会产生一个请求数据包(清单 7)。

  清单 7. getProducts()的一个示例SOAP请求

  以下是引用片段:
  <?xml version="1.0" encoding="UTF-8"?>
  <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope
  xmlns:ns1="http://example.localhost/index/soap
  xmlns:xsd="http://www.w3.org/2001/XMLSchema
  xmlns:enc="http://www.w3.org/2003/05/soap-encoding">
  <env:Body>
  <ns1:getProducts env:encodingStyle="http://www.w3.org/2003/05/soap-encoding"/>
  </env:Body>
  </env:Envelope>


  这个服务器产生一个使用SOAP编码的响应(清单 8)。

  清单 8. getProducts() 函数的一个示例SOAP响应

  以下是引用片段:
  <?xml version="1.0" encoding="UTF-8"?>
  <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope
  xmlns:ns1="http://example.localhost/index/soap
  xmlns:ns2="http://xml.apache.org/xml-soap
  xmlns:enc="http://www.w3.org/2003/05/soap-encoding
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc">
  <ns1:getProductsResponse 
  env:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
  <rpc:result>return</rpc:result>
  <return enc:itemType="ns2:Map" enc:arraySize="2" xsi:type="enc:Array">
  <item xsi:type="ns2:Map">
  <item>
  <key xsi:type="xsd:string">id</key>
  <value xsi:type="xsd:string">1</value>
  </item>
  <item>
  <key xsi:type="xsd:string">title</key>
  <value xsi:type="xsd:string">Ride Along Fire Engine</value>
  </item>
  <item>
  <key xsi:type="xsd:string">shortdesc</key>
  <value xsi:type="xsd:string">This red fire engine is ideal 
  for toddlers who want to travel independently. 
  Comes with flashing lights and beeping horn.</value>
  </item>
  <item>
  <key xsi:type="xsd:string">price</key>
  <value xsi:type="xsd:string">69.99</value>
  </item>
  <item>
  <key xsi:type="xsd:string">quantity</key>
  <value xsi:type="xsd:string">11</value>
  </item>
  </item>
  ...
  </return>
  </ns1:getProductsResponse>
  </env:Body>
  </env:Envelope>


  然后SOAP客户端会将这个响应转换成一个原生的PHP数组,它可以被进一步处理或检查,如 图 2 所示。 

 

  图 2. 被转换成一个原生PHP数组的SOAP请求结果

0
相关文章