December 25, 2006

とりあえず、ソースコード吐いていいかね。Services_HotPepper-0.1.0?(訂正)

というわけで、ライブラリが出てきたっぽいので、そちらにリンクを貼って、こっちのソースコードは消すよー。だいたい同じ感じのAPIで、そちらの方が完成度が高そうだったので。でも、少しだけ使用方法が違ったので、それを修正したよー。
過去と他人はかえられないが、未来と自分はかえられる - Services_HotPepper-0.1.1

とりあえず、ライセンスは放棄しておく。なので、自由に改変してもいいし、配布してもいいです。ライセンス周りは結構面倒なのよ。なので、やる気が出てちゃんとメンテする気が出るまでライセンスは放棄でよろしく。単にGoogle Mapsと連携してみたかっただけなので。

で、ライブラリの方のソースコードは、Exception周りをちゃんとチェックしていないので、よくわからないけど、今回作ったHotPepperのAPIとGoogle Mapsのマッシュアップのソースの公開でもしてみる。適当に自己責任で使ってくれ。名前を変更して、追加開発しても構いませんよ。前回のポストにも書いたけど、すでに名前があると、なんかややこいけど、いいライブラリが出てきたらServices_の接頭辞を消しますよー。例によって、PHP5で、Curlが必要。Cache_Liteもあると激しくよい。つーか、パッケージ化すればいいのか。なんかやる気がないのが困ったものだ。需要があれば、してみるけど、ちょっと様子見。

アプリの方は、Pagerがないとダメ。あと、0.1.0 では、

で、これを使うと、マスタ系APIとグルメサーチができる。

  1. $hotpepper = new Services_HotPepper();
  2.  
  3. // 大サービスエリアコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#021
  4. $data = $hotpepper->getLargeServiceArea();
  5. var_dump($data);
  6. // サービスエリアコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#022
  7. $data = $hotpepper->getServiceArea();
  8. var_dump($data);
  9. // 大エリアコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#023
  10. $data = $hotpepper->getLargeArea();
  11. var_dump($data);
  12. // 中エリアコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#024
  13. $data = $hotpepper->getMiddleArea();
  14. var_dump($data);
  15. // 小エリアコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#025
  16. $data = $hotpepper->getSmallArea();
  17. var_dump($data);
  18. // お店ジャンルコードの内容を取得 詳細: http://api.hotpepper.jp/reference.html#026
  19. $data = $hotpepper->getGenre();
  20. var_dump($data);
  21. // 予算のコード内容を取得 詳細: http://api.hotpepper.jp/reference.html#027
  22. $data = $hotpepper->getBudget();
  23. var_dump($data);
  24.  
  25. // グルメサーチAPIの内容を取得
  26. // $parametersの内容は、リクエストパラメータのハッシュ http://api.hotpepper.jp/reference.html#002
  27. $data = $hotpepper->getGourmetSearch($parameters);
  28. var_dump($data);

これだけではありがた味がわからないので、それを使って、検索結果の店の住所からGoogle Mapsにプロットしてみるのが次のコード。はい。ツッコミされまくりそうですね。

  1. <?php
  2. require_once 'Services/Hotpepper.php';
  3. require_once 'Pager.php';
  4.  
  5. class HotPepperApp
  6. {
  7.     private $hotpepper;
  8.     private $searchResult;
  9.     private $parameters;
  10.  
  11.     const DEFAULT_ADDRESS = '東京';
  12.  
  13.     public function __construct($parameters = array())
  14.     {
  15.         $this->hotpepper = new Services_Hotpepper();
  16.         $this->hotpepper->setResponseFormat('array');
  17.         $this->hotpepper->setUseCache(true);
  18.         $this->parameters = $parameters;
  19.         if (isset($this->parameters['Start'])) {
  20.             if (!isset($this->parameters['Count'])) {
  21.                 $this->parameters['Count'] = 10;
  22.             }
  23.             $this->parameters['Start'] *= (int)$this->parameters['Count'];
  24.         }
  25.         // 2006-12-25T16:03:16 修正 parametersに使えない値があるとInvalidParamerExceptionを吐くので、とりあえずそれ以外は削る。
  26.         $availables = array(
  27.           'ShopIdFront', 'ShopNameKana', 'ShopName', 'ShopTel', 'ShopAddress',
  28.           'KtaiCoupon', 'LargeServiceAreaCD', 'ServiceAreaCD', 'LargeAreaCD',
  29.           'MiddleAreaCD', 'SmallAreaCD', 'Keyword', 'GenreCD', 'Order',
  30.           'Start', 'Count');
  31.         foreach ($this->parameters as $key => $value) {
  32.             if (!in_array($key, $availables) or $value == '') {
  33.                 unset($this->parameters[$key]);
  34.             }
  35.         }
  36.     }
  37.  
  38.     public function getOptions($master)
  39.     {
  40.         $method = 'get' . $master;
  41.         $result = $this->hotpepper->$method();
  42.  
  43.         $output = '<select name="' .$master. 'CD">';
  44.         $output .= '<option value="">&nbsp;-&nbsp;</option>';
  45.         foreach ($result[$master]  as $item) {
  46.             $output .= '<option value="' . $item[$master.'CD'] . '"';
  47.             if (isset($_REQUEST[$master.'CD']) and $_REQUEST[$master.'CD'] == $item[$master.'CD']) {
  48.                 $output .= ' selected="selected"';
  49.             }
  50.             $output .= '>' . $item[$master .'Name'] . '</option>';
  51.         }
  52.         $output .= '</select>';
  53.         return $output;
  54.     }
  55.  
  56.     public function getResult()
  57.     {
  58.         if (!isset($_REQUEST['search'])) { return array(); }
  59.         $output = '';
  60.         if (empty($this->searchResult)) {
  61.             $this->searchResult = $this->hotpepper->getGourmetSearch($this->parameters);
  62.         }
  63.         if (is_null($this->searchResult['NumberOfResults'])) { return array(); }
  64.         return $this->searchResult['Shop'];
  65.     }
  66.  
  67.     public function getPager()
  68.     {
  69.         if (!isset($this->parameters)) { return ''; }
  70.         if (empty($this->searchResult)) {
  71.             $this->searchResult = $this->hotpepper->getGourmetSearch($this->parameters);
  72.         }
  73.         $options = array(
  74.             'mode'         => 'Sliding',
  75.             'urlVar'       => 'Start',
  76.             'totalItems'   => (int)$this->searchResult['NumberOfResults'] - (int)$this->searchResult['DisplayPerPage'],
  77.             'perPage'      => (int)$this->searchResult['DisplayPerPage'],
  78.             'currentPage'  => (int)$this->searchResult['DisplayFrom'] / (int)$this->searchResult['DisplayPerPage'],
  79.         );
  80.  
  81.         $pager = Pager::factory($options);
  82.         return $pager->links;
  83.     }
  84.  
  85.     public function getShopAddress()
  86.     {
  87.         return isset($_REQUEST['ShopAddress']) ? htmlspecialchars($_REQUEST['ShopAddress']) : self::DEFAULT_ADDRESS;
  88.     }
  89.  
  90.     // Helper Method
  91.     public static function getTabHtml($result)
  92.     {
  93.         $url          = htmlspecialchars($result['ShopUrl']);
  94.         $name         = htmlspecialchars($result['ShopName']);
  95.         $address      = htmlspecialchars($result['ShopAddress']);
  96.         $noKtaiCoupon = (boolean)$result['KtaiCoupon'];
  97.         $access       = htmlspecialchars($result['Access']);
  98.         $genre        = htmlspecialchars($result['GenreName']);
  99.         $catch        = htmlspecialchars($result['ShopCatch']);
  100.         $budget       = htmlspecialchars($result['BudgetDesc']);
  101.         $capacity     = htmlspecialchars($result['Capacity']);
  102.         $ktaiShopUrl  = htmlspecialchars($result['KtaiShopUrl']);
  103.         $image        = htmlspecialchars($result['PictureUrl']['PcMiddleImg']);
  104.  
  105.         $ktaiText = $isKtaiCoupon ? '携帯NG!' : '携帯OK!';
  106.  
  107.         $base =<<<eof
  108. <a href='$url'>$name($ktaiText)<br />$catch<br /><hr />$address<br />
  109. <!-- HotPepperのページからメールを送ればいいんじゃない?
  110. <form>
  111. <lable>携帯にアクセス先アドレスを:<input type='text' name='email'/>
  112. <input type='hidden' name='url' value='$ktaiShopUrl'/>
  113. <input type='submit' value='送信!'/>
  114.  
  115. -->
  116. EOF;
  117.         $detail =<<<eof
  118. <div style='float:left;width=200;text-align:center;'>
  119. <img src='$image' alt='$name' /><br />写真提供:ホットペッパー.jp<br />
  120.  
  121. <div>
  122. ジャンル($genre)<br />予算($budget)<br />総席数($capacity)
  123. <hr />
  124. $access
  125. </div>
  126. EOF;
  127.         $tab = array(
  128.             '店情報'   => str_replace("\n", "", $base),
  129.             '詳細情報' => str_replace("\n", "", $detail)
  130.         );
  131.         return $tab;
  132.     }
  133. }
  134.  
  135. if (isset($_REQUEST['search'])) {
  136.     $app = new HotPepperApp($_REQUEST);
  137. } else {
  138.     $app = new HotPepperApp;
  139. }
  140.  
  141. ?>
  142. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  143. <html xmlns="http://www.w3.org/1999/xhtml">
  144.   <head>
  145.     <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  146.     <title>Google Maps JavaScript API Example</title>
  147.     <!-- http://localhost/ -->
  148.  
  149. <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAvkm9X7SZvAyCad0c7GjwBhT2yXp_ZAY8_ufC3CFXhHIE1NvwkxRo7UhGG5tiSNLbTXH8AFUQzXffZg"
  150.     type="text/javascript"></script>
  151.  
  152. <!-- http://www.ganchiku.com/ -->
  153. <!--
  154.     <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAvkm9X7SZvAyCad0c7GjwBhR3SquV7UZw5piZBM9SKA5Ap0BlHxRIXFNr6SBh14IfS1Z5EVaMbEE3jw"
  155.       type="text/javascript">
  156. -->
  157. <script type="text/javascript">
  158.  
  159. //<![CDATA[
  160.  
  161. function load() {
  162.     if (GBrowserIsCompatible()) {
  163.         var map = new GMap2(document.getElementById("map"));
  164.         var geocoder = new GClientGeocoder();
  165.         var address = '<?php echo $app->getShopAddress(); ?>';
  166.         map.addControl(new GLargeMapControl());
  167.         map.addControl(new GMapTypeControl());
  168.         map.addControl(new GOverviewMapControl());
  169.         geocoder.getLatLng(address, function(point) {
  170.             if (!point) {
  171.                 alert("存在する住所(一部可)を入力してください。");
  172.             } else {
  173.                 map.setCenter(point, 13);}
  174.         });
  175.     }
  176.     var shopAddress = '';
  177.     <?php foreach ($app->getResult() as $result) : ?>
  178.     shopAddress = '<?php echo array_shift(explode(" ", $result['ShopAddress'])); ?>';
  179.     geocoder.getLatLng(shopAddress, function(point) {
  180.         if (point) {
  181.             var marker = new GMarker(point);
  182.             var windowTabs = [
  183.                 <?php foreach (HotPepperApp::getTabHtml($result) as $tab => $content) : ?>
  184.                 new GInfoWindowTab("<?php echo $tab; ?>", "<?php echo $content; ?>"),
  185.                     <?php endforeach; ?>
  186.                     ];
  187.             map.addOverlay(marker);
  188.             GEvent.addListener(marker, "click", function() {
  189.                 marker.openInfoWindowTabsHtml(windowTabs);
  190.             });
  191.         }
  192.     });
  193.     <?php endforeach; ?>
  194. }
  195.  
  196. //]]>
  197. </script>
  198.   </head>
  199.   <body onload="load()" onunload="GUnload()">
  200.     <div id="form">
  201.     <form method="get" action="hotpepper.php">
  202.     <input type="text" name="ShopAddress" value="<?php echo $app-/>getShopAddress(); ?>" size="64" maxlength="128">
  203.     <?php echo $app->getOptions('Genre'); ?>
  204.     <select name="Count">
  205. <?php
  206. for($i = 0; $i <10; $i++)  {
  207.     $value = ($i+1) * 10;
  208.     echo '<option value="'.$value.'"';
  209.     if (isset($_REQUEST['Count']) and $_REQUEST['Count'] == $value) {
  210.         echo ' selected="selected"';
  211.     }
  212.     $output .= '>' . $item[$master .'Name'] . '';
  213.     echo '>'.$value.'件';
  214. }
  215. ?>
  216.     </select>
  217.     <input name="search" type="submit" value="検索"/>
  218.     </form>
  219.     <?php if (isset($_REQUEST['search'])) { echo '<br />' . $app->getPager(); } ?>
  220.     </div>
  221. <br />
  222.     <div id="map" style="width: 800px; height: 600px"></div>
  223.  
  224. Powered by <a href="http://www.hotpepper.jp/">ホットペッパー.jp</a>, <a href="http://maps.google.com/maps">GoogleMap</a>
  225.  
  226.   </body>
  227. </html>

まぁ、詳細はどうでもいいけど、HotPepperのAPIから帰ってくる住所は、建物の名前まで返ってくるので、それは削っている。あと、Pagerは、適当にtotalItemsに NumberOfResultsを - DisplayPerPageで引いた値を入れておく。最後のページのところで問題があるので。まぁ、本当はもう少しスマートにできるんだろうけど。

で、このソースから、少しだけ修正してあるけど、HotPeppe APIとGoogleMapのMashUpができあがる。まぁ、暇なときに作成したプロダクトとしてはこんなもんじゃない?まぁ、前から言っているように、食べログも使いたいので、これで終わりではない。。。予定。

うまいこと食べログを使うことができたら、価格.com WEBサービスAPIコンテストでも参加してみようかな。つーか、こういうのはどんどんやって欲しいね。HotPepperだったら、クーポン載せるの結構高いんでしょ?いっぱい宣伝してもらった方が、店もうれしいし、リクルートもうれしいし、Win-Win Situationじゃないのかね。そして、コンテストで買った人がお金とかもらえてうれしかったら、さらにいいじゃない?なんか、Web2.0ではお金儲けにならないって、どこかで読んだけど、こういうパターンだったらお金儲けになるんじゃない?

というわけで、メリークリスマス。

Shinさん早すぎいぃ~
こちらでもPEARパッケージ作ったのですが公開してもいいですかね?
もしくは、ほとんどServices_KakakuComを真似ただけなのでShinさんの所でもいいかな思っているのですが
どうでしょうか?

Comment by magiwo — December 25, 2006

[…] 追記(2006年12月26日): 過去と他人はかえられないが、未来と自分はかえられる - Services_Hotpepper(PHP5用ライブラリ) GANCHIKU.com » とりあえず、ソースコード吐いていいかね。Services_HotPepper-0.1.0?(訂正) ホットペッパーAPI を地図ベースのツール化作戦 (hiyuzawa.jpn.org)(GoogleMaps版はマーカーにオンマウスするとレストラン情報が表示されてスマートなインターフェイス。YahooMaps版もある) […]

> magiwoさん。
ごめんなさい。なんでかしらないけど、スパムチェックに引っかかってた。。。たまに、スパムの方を見ると実は本当のコメントやトラックバックがあったりするだよねー。

というわけで、Services_Hotpepperよろしこですー。

Comment by shin — December 26, 2006

Leave a comment

Bloglines feedburner