在yii中soap协议的配备和使用

在yii中soap协议的配备和使用

1,定义Service Provider
Yii依靠文档注解(doc comments)和类反射(class reflection)来识别哪个方法可以被远程调用,包括他们的参数和返回值。

我们定义服务器端的类,继承CController,如下面的例子所示:

class StockController extends CController{
	/**
	* @param String         the symbol of the stock
	* @return float         the stock price
	* @soap
	*/
	public function getPrice($symbol){
		$prices = array('IBM'=>100, 'GOOGLE'=>350);
		return isset($prices[$symbol]) ? $prices[$symbol] : 0;
		// ... return stock price for $symbol
	}
}

在上面的例子中,我们定义了方法getPrice(使用@soap)作为一个可供远程调用的API,并且通过文档注解(doc comments)来指定参数和返回值的数据类型。

批注:后面会讲数据类型可分为基本数据类型和复合数据类型。

2,定义 Web Service Action
既然前面已知服务器端类是继承自CController,所以需要定义一个action,将服务暴露出去。继续上面的例子,我们仅仅在StockController增加如下代码:

class StockController extends CController{
	/***********  增加  start  **************/
	public function actions(){
		return array(
			'quote'=>array(
				'class'=>'CWebServiceAction'
			),
		);
	}
	/***********  增加  end  **************/


	/**
	* @param String         the symbol of the stock
	* @return float         the stock price
	* @soap
	*/
	public function getPrice($symbol){
		$prices = array('IBM'=>100, 'GOOGLE'=>350);
		return isset($prices[$symbol]) ? $prices[$symbol] : 0;
		// ... return stock price for $symbol
	}
}

至此,如果我们访问地址:http://hostname/path/to/index.php?r=stock/quote
我们将得到一个包含大量XML格式的内容,实际上它就是上面Web Service定义的WSDL。

批注:缺省情况下,CWebServiceAction默认当前controller就是Service Provider,这就是为什么上面直接在StockController里定义getPrice方法。

3,在客户端调用:(可以使用多种语言)

$client = new SoapClient('http://hostname/path/to/index.php?r=stock/quote');
echo $client->getPrice('GOOGLE');

//运行上面的脚本,通过Web或命令行方式,可以得出结果:350

4,关于参数和返回值的数据类型
在实际应用中,参数和返回值的数据类型可分为基本数据类型和复合数据类型。

(1)基本类型数据
string , integer , float, boolean, date, time, datetime, array , object, mixed

(2)复合类型数据
如果是复合数据类型,则复合数据类型会通过类的形式表示,这时它的每一个public的数据项都需要使用@soap来进行文档注解(doc comments)。例如:

class outsource_header {
	/**
	 * @var string 访问密钥, a和b之间的访问控制
	 * @soap
	 */
	public $token;

	/**
	 * @var integer 外包单号
	 * @soap
	 */
	public $id;

	/**
	 * @var string 该外包单对应的机房名称
	 * @soap
	 */
	public $idc_name;

	/**
	 * @var outsource_handler 处理人信息
	 * @soap
	 */
	public $handler;	// 处理人信息
}

需要注意的是,如果想让client端收到复合类型数据,除了上面给出的类定义外,还需要在Service Provider的actions方法里增加配置项classMap=>array(‘outsource_header’)。如下面所示:

class XXController extends CController{
	public function actions(){
		return array(
			'service'=>array(
				'class'=>'CWebServiceAction',
				//增加  classMap 配置项
				'classMap'=>array(
					'outsource_header',
				),
			),
		);
	}
}

此外,复合数据类型也可以使用数组(Array),通过[]向基本数据类型或复合数据类型的末尾追加的方式。例如,

class PostController extends CController{
	/**
	* @return Post[]       a list of posts
	* @soap
	*/
	public function getPosts(){
		return Post::model()->findAll();
	}
}
class Post extends CActiveRecord{
	/**
	 * @var integer    post ID
	 * @soap
	 */
	public $id;
	/**
	 * @var string     post title
	 * @soap
	 */
	public $title;

	public static function model($className=__CLASS__){
		return parent::model($className);
	}
}

该实例,调用getPosts方法时,将返回一个数组。

5,拦截远程方法调用(Intercepting Remote Method Invocation)
通过实现[IWebServiceProvider]接口,可以拦截所有方法,在[IWebServiceProvider::beforeWebMethod],这个provider可以获取当前CWebService实例,并通过CWebService::methodName来获取当前请求的方法名,它可以返回false,如果这个远程方法因某些原因(比如未经授权的访问)不应被调用。

0 Comments
Leave a Reply