それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Services_AmazonをsimpleXMLにする。

Services_AmazonのキャッシュをCache_Liteに変更。Services_Amazonの結果をSimpleXmlに変更。Services_Amazonは_sendRequest()以外に拡張できるメソッドが無いので結構手間だった。_sendRequest()内でキャッシュの処理を行ったりXMLのParseしちゃってる。TemplateMethodにしてくれてるとClassをExtendsして拡張しやすかったのだけれど。

SimpleXMLで結果を取り出すとServices_Amazonを使う意味があまりなくなるのだけれど。。。。PEARのBugにRequestとして挙がってるのでそのうち対応されるのだろうけど。待ってられない。

class Utena_Amazon extends Services_AmazonECS4 {
  //継承するのでついでにIDを直書きする。
  const AWS_TOKEN ="****";
  const AA_ID     ="utena-22";
  //レスポンスのXML
  public $raw_xml = "";
  public function __construct(){
    parent::__construct(Utena_Amazon::AWS_TOKEN,Utena_Amazon::AA_ID);
    $this->setVersion('2007-02-22');
  }
  //Localeに自前プロキシサーバーを追加
  public function setLocale($locale){
    $urls = array(
      'US' => 'http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService',
      'UK' => 'http://ecs.amazonaws.co.uk/onca/xml?Service=AWSECommerceService',
      'DE' => 'http://ecs.amazonaws.de/onca/xml?Service=AWSECommerceService',
      'JP' => 'http://ecs.amazonaws.jp/onca/xml?Service=AWSECommerceService',
      'FR' => 'http://ecs.amazonaws.fr/onca/xml?Service=AWSECommerceService',
      'CA' => 'http://ecs.amazonaws.ca/onca/xml?Service=AWSECommerceService',

    );
    //cache server
    $urls["UTENA"] = "http://api.bookmacro.com/amazon?Service=AWSECommerceService";
    $locale = strtoupper($locale);
    if (empty($urls[$locale])) {
      return PEAR::raiseError('Invalid locale');
    }
    $this->setBaseUrl($urls[$locale]);
    return true;
  }
  //SimilarityLookupをArray対応にする。
  //http://pear.php.net/bugs/bug.php?id=10687
  //に報告済み
  function SimilarityLookup($item_id, $options = array())
  {
    if(is_array($item_id)){
      $item_id = implode(",", $item_id);
    }
    return parent::SimilarityLookup($item_id,$options);
  }
  //URL組み立て部分を切り出し。
  protected function _RestURI($params){
    $params['AWSAccessKeyId'] = $this->_keyid;
    $params['AssociateTag'] = $this->_associd;
    $params['Version'] = $this->_version;
    $url = $this->_baseurl;
    if(!$url){
      return PEAR::raiseError("Request End Point have not set yet");
    }
    foreach ($params as $k => $v) {
      $url .= '&' . $k . '=' . urlencode($v);
    }
    return $url;
  }
  //Cache_Liteに切り替え
  protected function setCache($container = 'file', $container_options = array()){ 
    if(!class_exists('Cache_Lite')){
      @include_once 'Cache_Lite.php';
    }
    @$cache = new Cache_Lite($container_options);
    if (is_object($cache)) {
      $this->_cache = $cache;
      return true;
    } else {
      $this->_cache = null;
      return parent::setCache($container,$container_options);
    }
  }
  //Cacheに何か処理をフックするポイント
  protected function _getCache($cache_id){
    if( $this->_cache == null ){
      return null;
    }
    if( $data = $this->_cache->get($cache_id) ){
      return simplexml_load_string($data);
    }
    return null;
  }
  //Cache_LiteとCacheはAPIが違うのでここで差異を吸収する
  protected function _setCache($cache_id, $data){
    if( $this->_cache == null ){
      return null;
    }
    $this->_cache->save($data->asXML(), $cache_id, $this->_cache_expire);
  }
  protected function _httpRequest($url){
    //HTTP通信を切り替える
    if($this->_cache != null){
      $res = $this->_cache->get( md5(strstr($url, "?")) );
      if( $res ){
        return $res;
      }
    }
    //////////////
    $http = &new HTTP_Request($url);
    $http->setHttpVer('1.0');
    $http->addHeader(
            'User-Agent',
            'Utena_Amazon/'.$this->getApiVersion()
           );
    $http->sendRequest();
    $http->disconnect();
    if ($http->getResponseCode() != 200){
      return PEAR::raiseError(
        'Amazon returned invalid HTTP response code '
        . $http->getResponseCode()
      );
    }
    $res = $http->getResponseBody();
    if( PEAR::isError($res)){
      return PEAR::raiseError("HTTP Request Error");
    }
    if($this->_cache != null){
      $this->_cache->save( md5( strstr($url, "?")), $res );
    }
    return $res;
  }
  protected function _parseResponse($result){
    //ココを切り替えることでsimpleXMLにする
    $result = str_replace("xmlns", "_xmlns", $result);
    $this->raw_xml = $result;
    $xml = simplexml_load_string($result);
    //何を返却するか・・・
    //何をキャッシュするべきか
    if( isset($xml->Errors) ){
      $str;
      foreach( $xml->Error as $error ){
        $str .= "$error->Code:$error->Message\n";
      }
      return PEAR::raiseError($str);
    }
    //$this->_processing_time = $xml->{"RequestProcessingTime"};
    unset($xml["_xmlns"]);
    unset($xml->OperationRequest);
    return $xml;
  }
  public function _sendRequest($params){
    $this->_errors = array();
    if ($this->_keyid==null) {
      return PEAR::raiseError('Access Key ID have not been set');
    }
    $url = $this->_RestURI($params);
    $this->_lasturl = $url;
    if (PEAR::isError($url)) {
      return $url;
    }
    // Return cached data if available
    $cache_id = false;
    if (isset($this->_cache) && !$this->_ignoreCache($params['Operation'])) {
      $cache_id = $this->_generateCacheId($params);
    }
    if( $cache_id ){
      $cache = $this->_getCache( $cache_id );
      if (!is_null($cache)) {
        $this->_processing_time = 0;
        return $cache;
      }
    }
    //http request
    $result = $this->_httpRequest($url);
    if (PEAR::isError($result)) {
      var_dump($result);
      exit();
      return $result;
    }
    //parse XML
    $content = $this->_parseResponse($result);
    if (PEAR::isError($content)) {
      return PEAR::raiseError("Cannot Get Content.. ");
    }
    //cache 
    if ($cache_id) {
      $this->_setCache($cache_id,$content);
    }
    return $content;
  }
}