33.3.3 获得一个AmazonResultSet类
现在,我们来仔细了解getARS()函数,如程序清单33-7所示。
程序清单33-7 cachefunctions.php函数库中的getARS()函数——一个查询的结果集
//Get an AmazonResultSet either from cache or a live query
//If a live query add it to the cache
function getARS($type,$parameters){
$cache=cached($type,$parameters);
if($cache){
//if found in cache
return$cache;
}else{
$ars=new AmazonResultSet;
if($type=='asin'){
$ars->ASINSearch(padASIN($parameters['asin']),$parameters['mode']);
}
if($type=='browse'){
$ars->browseNodeSearch($parameters['browsenode'],
$parameters['page'],$parameters['mode']);
}
if($type=='search'){
$ars->keywordSearch($parameters['search'],$parameters['page'],
$parameters['mode']);
}
cache($type,$parameters,$ars);
}
return$ars;
}
这个函数是用来驱动从Amazon获得数据的操作。它可以以两种方式完成数据获取:从缓存,或者从Amazon实时获得。由于Amazon要求开发人员缓存已经下载的数据,因此这个函数将首先查看保存在缓存中的数据。我们将在稍后的内容详细介绍缓存。
如果我们还没有执行特定的查询操作,就必须从Amazon站点实时获得数据。通过创建一个AmazonResultSet类的实例,并且调用该类中对应于我们需要执行的查询的方法,可以获得实时数据。查询的类型是由$type参数决定的。以种类(或者浏览节点)查询为例,我们将browse传递给该参数——参阅程序清单33-6。如果我们希望执行一个针对特定图书的查询,就应该传递该图书的asin,而如果希望执行一个关键字查询,该参数就必须设置为search。
该参数的每一个不同值都将调用AmazonResultSet类中的不同方法。单个物品搜索将调用ASINSearch()方法。种类搜索将调用browseNodeSearch()方法。而关键字搜索将调用keywordSearch()方法。
下面,我们来仔细了解AmazonResultSet类。该类的所有代码如程序清单33-8所示。
程序清单33-8 AmazonResultSet.php——处理与Amazon站点连接的类
<?php
//you can switch between REST and SOAP using this constant set in
//constants.php
if(METHOD=='SOAP'){
include_once('nusoap/lib/nusoap.php');
}
//This class stores the result of queries
//Usually this is 1 or 10 instances of the Product class
class AmazonResultSet{
private$browseNode;
private$page;
private$mode;
private$url;
private$type;
private$totalResults;
private$currentProduct=null;
private$products=array();//array of Product objects
function products(){
return$this->products;
}
function totalResults(){
return$this->totalResults;
}
function getProduct($i){
if(isset($this->products[$i])){
return$this->products[$i];
}else{
return false;
}
}
//Perform a query to get a page full of products from a browse node
//Switch between XML/HTTP and SOAP in constants.php
//Returns an array of Products
function browseNodeSearch($browseNode,$page,$mode){
$this->Service="AWSECommerceService";
$this->Operation="ItemSearch";
$this->AWSAccessKeyId=DEVTAG;
$this->AssociateTag=ASSOCIATEID;
$this->BrowseNode=$browseNode;
$this->ResponseGroup="Large";
$this->SearchIndex=$mode;
$this->Sort='salesrank';
$this->TotalPages=$page;
if(METHOD=='SOAP'){
$soapclient=new nusoap_client(
'http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl',
'wsdl');
$soap_proxy=$soapclient->getProxy();
$request=array('Service'=>$this->Service,
'Operation'=>$this->Operation,'BrowseNode'=>$this->BrowseNode,
'ResponseGroup'=>$this->ResponseGroup,'SearchIndex'=>
$this->SearchIndex,'Sort'=>$this->Sort,'TotalPages'=>
$this->TotalPages);
$parameters=array('AWSAccessKeyId'=>DEVTAG,
'AssociateTag'=>ASSOCIATEID,'Request'=>array($request));
//perform actual soap query
$result=$soap_proxy->ItemSearch($parameters);
if(isSOAPError($result)){
return false;
}
$this->totalResults=$result['TotalResults'];
foreach($result['Items']['Item']as$product){
$this->products[]=new Product($product);
}
unset($soapclient);
unset($soap_proxy);
}else{
//form URL and call parseXML to download and parse it
$this->url="http://ecs.amazonaws.com/onca/xml?".
"Service=".$this->Service.
"&Operation=".$this->Operation.
"&AssociateTag=".$this->AssociateTag.
"&AWSAccessKeyId=".$this->AWSAccessKeyId.
"&BrowseNode=".$this->BrowseNode.
"&ResponseGroup=".$this->ResponseGroup.
"&SearchIndex=".$this->SearchIndex.
"&Sort=".$this->Sort.
"&TotalPages=".$this->TotalPages;
$this->parseXML();
}
return$this->products;
}
//Given an ASIN,get the URL of the large image
//Returns a string
function getImageUrlLarge($ASIN,$mode){
foreach($this->products as$product){
if($product->ASIN()==$ASIN){
return$product->imageURLLarge();
}
}
//if not found
$this->ASINSearch($ASIN,$mode);
return$this->products(0)->imageURLLarge();
}
//Perform a query to get a products with specified ASIN
//Switch between XML/HTTP and SOAP in constants.php
//Returns a Products object
function ASINSearch($ASIN,$mode='books'){
$this->type='ASIN';
$this->ASIN=$ASIN;
$this->mode=$mode;
$ASIN=padASIN($ASIN);
$this->Service="AWSECommerceService";
$this->Operation="ItemLookup";
$this->AWSAccessKeyId=DEVTAG;
$this->AssociateTag=ASSOCIATEID;
$this->ResponseGroup="Large";
$this->IdType="ASIN";
$this->ItemId=$ASIN;
if(METHOD=='SOAP'){
$soapclient=new nusoap_client(
'http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl',
'wsdl');
$soap_proxy=$soapclient->getProxy();
$request=array('Service'=>$this->Service,'Operation'=>
$this->Operation,'ResponseGroup'=>$this->ResponseGroup,
'IdType'=>$this->IdType,'ItemId'=>$this->ItemId);
$parameters=array('AWSAccessKeyId'=>DEVTAG,
'AssociateTag'=>ASSOCIATEID,'Request'=>array($request));
//perform actual soap query
$result=$soap_proxy->ItemLookup($parameters);
if(isSOAPError($result)){
return false;
}
$this->products[0]=new Product($result['Items']['Item']);
$this->totalResults=1;
unset($soapclient);unset($soap_proxy);
}else{
//form URL and call parseXML to download and parse it
$this->url="http://ecs.amazonaws.com/onca/xml?".
"Service=".$this->Service.
"&Operation=".$this->Operation.
"&AssociateTag=".$this->AssociateTag.
"&AWSAccessKeyId=".$this->AWSAccessKeyId.
"&ResponseGroup=".$this->ResponseGroup.
"&IdType=".$this->IdType.
"&ItemId=".$this->ItemId;
$this->parseXML();
}
return$this->products[0];
}
//Perform a query to get a page full of products with a keyword search
//Switch between XML/HTTP and SOAP in index.php
//Returns an array of Products
function keywordSearch($search,$page,$mode='Books'){
$this->Service="AWSECommerceService";
$this->Operation="ItemSearch";
$this->AWSAccessKeyId=DEVTAG;
$this->AssociateTag=ASSOCIATEID;
$this->ResponseGroup="Large";
$this->SearchIndex=$mode;
$this->Keywords=$search;
if(METHOD=='SOAP'){
$soapclient=new nusoap_client(
'http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl',
'wsdl');
$soap_proxy=$soapclient->getProxy();
$request=array('Service'=>$this->Service,'Operation'=>
$this->Operation,'ResponseGroup'=>$this->ResponseGroup,
'SearchIndex'=>$this->SearchIndex,'Keywords'=>$this->Keywords);
$parameters=array('AWSAccessKeyId'=>DEVTAG,
'AssociateTag'=>ASSOCIATEID,'Request'=>array($request));
//perform actual soap query
$result=$soap_proxy->ItemSearch($parameters);
if(isSOAPError($result)){
return false;
}
$this->totalResults=$result['TotalResults'];
foreach($result['Items']['Item']as$product){
$this->products[]=new Product($product);
}
unset($soapclient);
unset($soap_proxy);
}else{
$this->url="http://ecs.amazonaws.com/onca/xml?".
"Service=".$this->Service.
"&Operation=".$this->Operation.
"&AssociateTag=".$this->AssociateTag.
"&AWSAccessKeyId=".$this->AWSAccessKeyId.
"&ResponseGroup=".$this->ResponseGroup.
"&SearchIndex=".$this->SearchIndex.
"&Keywords=".$this->Keywords;
$this->parseXML();
}
return$this->products;
}
//Parse the XML into Product object(s)
function parseXML(){
//suppress errors because this will fail sometimes
$xml=@simplexml_load_file($this->url);
if(!$xml){
//try a second time in case just server busy
$xml=@simplexml_load_file($this->url);
if(!$xml){
return false;
}
}
$this->totalResults=(integer)$xml->TotalResults;
foreach($xml->Items->Item as$productXML){
$this->products[]=new Product($productXML);
}
}
}
这个类是非常有用的。它以非常好的黑盒方式封装了与Amazon站点的接口。在这个类中,与Amazon站点的连接可以通过REST方法或SOAP方法来实现。所使用的方法通过在最开始的constants.php文件设置的全局常量METHOD来确定。
下面,让我们回到前面的种类搜索例子。我们按如下方式使用AmazonResultSet:
$ars=new AmazonResultSet;
$ars->browseNodeSearch($parameters['browsenode'],
$parameters['page'],
$parameters['mode']);
这个类没有构造函数,因此我们直接介绍browseNodeSearch()方法。这里,我们将向该方法传递3个参数:我们所感兴趣的browsenode号(相应地,例如,"Business&Investing"或者"Computers&Internet");表示要获得多少记录的页数;以及表示我们所感兴趣的商业类型的模式。该方法的代码如程序清单33-9所示。
程序清单33-9 browseNodeSearch()方法——执行一个种类查询
//Perform a query to get a page full of products from a browse node
//Switch between XML/HTTP and SOAP in constants.php
//Returns an array of Products
function browseNodeSearch($browseNode,$page,$mode){
$this->Service="AWSECommerceService";
$this->Operation="ItemSearch";
$this->AWSAccessKeyId=DEVTAG;
$this->AssociateTag=ASSOCIATEID;
$this->BrowseNode=$browseNode;
$this->ResponseGroup="Large";
$this->SearchIndex=$mode;
$this->Sort="salesrank";
$this->TotalPages=$page;
if(METHOD=='SOAP'){
$soapclient=new nusoap_client(
'http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl',
'wsdl');
$soap_proxy=$soapclient->getProxy();
$request=array('Service'=>$this->Service,
'Operation'=>$this->Operation,'BrowseNode'=>$this->BrowseNode,
'ResponseGroup'=>$this->ResponseGroup,'SearchIndex'=>
$this->SearchIndex,'Sort'=>$this->Sort,'TotalPages'=>
$this->TotalPages);
$parameters=array('AWSAccessKeyId'=>DEVTAG,
'AssociateTag'=>ASSOCIATEID,'Request'=>array($request));
//perform actual soap query
$result=$soap_proxy->ItemSearch($parameters);
if(isSOAPError($result)){
return false;
}
$this->totalResults=$result['TotalResults'];
foreach($result['Items']['Item']as$product){
$this->products[]=new Product($product);
}
unset($soapclient);
unset($soap_proxy);
}else{
//form URL and call parseXML to download and parse it
$this->url="http://ecs.amazonaws.com/onca/xml?".
"Service=".$this->Service.
"&Operation=".$this->Operation.
"&AssociateTag=".$this->AssociateTag.
"&AWSAccessKeyId=".$this->AWSAccessKeyId.
"&BrowseNode=".$this->BrowseNode.
"&ResponseGroup=".$this->ResponseGroup.
"&SearchIndex=".$this->SearchIndex.
"&Sort=".$this->Sort.
"&TotalPages=".$this->TotalPages;
$this->parseXML();
}
return$this->products;
}
根据METHOD常量值的不同,这个方法将执行通过基于SOAP或REST的查询。但是,这两种请求中发送的信息是相同的。如下代码行显示的是请求的变量及其值:
$this->Service="AWSECommerceService";
$this->Operation="ItemSearch";
$this->AWSAccessKeyId=DEVTAG;
$this->AssociateTag=ASSOCIATEID;
$this->BrowseNode=$browseNode;
$this->ResponseGroup="Large";
$this->SearchIndex=$mode;
$this->Sort="salesrank";
$this->TotalPages=$page;
以上代码中的某些变量值是在应用的其他部分设置,例如,$browseNode、$mode和$page的变量值。其他值是常量,例如,DEVTAG和ASSOCIATEID.。而另外一部分的变量$this->Service和$this->Operation以及$this->Sort都是静态变量。
不同的请求类型对变量的要求是不同。以上示例用来浏览根据销售排名的特定节点。查询特定物品和关键字的变量是不同的。在AmazonResultSet.php文件的browseNodeSearch()函数、ASINSearch()函数以及keywordSearch()函数中,你可以找到这些变量的列表。所有请求类型所需变量的详细信息可以在AWS开发人员指南找到。
接下来,我们分别介绍browseNodeSearch()函数中的REST和SOAP查询请求的创建。ASINSearch()函数和keywordSearch()函数的请求创建格式在概念上都是相似的。