4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

(XML版)ホットペッパーAPIからレストラン検索するサンプル その2

Last updated at Posted at 2016-10-11

##各種リファレンス

###GoogleMaps

Google Maps API> ウェブ向け > Maps JavaScript API > スタートガイド
Google Maps API> ウェブ向け > Maps JavaScript API > マーカー

###JavaScript

JavaScript リファレンス

###PHP

PHP関数リファレンス

foreach
if
制御構造に関する別の構文
return
htmlspecialchars
require_once
number_format
isset
is_object
代数演算子
filter_input
filter_input_array
sprintf
simplexml_load_file
is_null
ceil
http_build_query
implode

##ソースコード

index.php
<?php
/**
 * index.php
 *
 * @since 2016/08/06
 */
require_once './Hpepper.class.php';

/**
 * エスケープ
 * これを通さずに出力すると、XSS脆弱性で任意のJavaScriptが実行されてしまう。
 * 
 * @param string $string
 * @return string
 */
function h($string)
{
	return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

// 料理カテゴリ
$food_category = Hpepper::getFoodCategory();

// 予算
$budget = Hpepper::getBudget();

// クレジットカード
$credit_card = Hpepper::getCreditCard();

// 大サービスエリア
$large_service_area = Hpepper::getLargeServiceArea();

// サービスエリア
$service_area = Hpepper::getServiceArea();

// レストラン検索
$restaurants = Hpepper::getRestaurants();

// ドキュメントの頭で、echo しない。
// ここで echo すると、<html> tagよりも前で文字列を出力してしまい、html 文法に違反する。
?>
<!DOCTYPE HTML>
<html lang="ja">
	<head>
		<meta charset="UTF-8">
		<title>ホットペッパーAPIテスト(アホでも設置するだけで動く)</title>
		<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
		<style type="text/css">
			.map {
				height: 300px;
			}
			.shop {
				margin-bottom: 2em;
			}
			.shop > div {
				border: 1px solid #CCC;
				padding: 1em;
			}
		</style>
	</head>
	<body>
		<div class="container">
			<h1>ホットペッパーAPIサンプル</h1>

			<form method="get">
				<div class="row">
					<div class="col-md-4">
						<div class="form-group">
							<label for="food_category">料理カテゴリ</label>
							<select class="form-control" name="food" id="food_category">
								<option value="">料理カテゴリ</option>
								<?php foreach ($food_category->food_category as $food_category) : ?>
									<?php if ($food_category->code == filter_input(INPUT_GET, 'food')): ?>
										<option value="<?= h($food_category->code); ?>" selected="selected">
											<?= h($food_category->name); ?>
										</option>
									<?php else: ?>
										<option value="<?= h($food_category->code); ?>">
											<?= h($food_category->name); ?>
										</option>
									<?php endif; ?>
								<?php endforeach; ?>
							</select>
						</div>

						<div class="form-group">
							<label for="budget">予算</label>
							<select class="form-control" name="budget" id="service_area">
								<option value="">予算</option>
								<?php foreach ($budget->budget as $budget) : ?>
									<?php if ($budget->code == filter_input(INPUT_GET, 'budget')): ?>
										<option value="<?= h($budget->code); ?>" selected="selected">
											<?= h($budget->name); ?>
										</option>
									<?php else: ?>
										<option value="<?= h($budget->code); ?>">
											<?= h($budget->name); ?>
										</option>
									<?php endif; ?>
								<?php endforeach; ?>
							</select>
						</div>

						<div class="form-group">
							<label for="credit_card">クレジットカード</label>
							<select class="form-control" name="credit_card" id="credit_card">
								<option value="">クレジットカード</option>
								<?php foreach ($credit_card->credit_card as $credit_card) : ?>
									<?php if ($credit_card->code == filter_input(INPUT_GET, 'credit_card')): ?>
										<option value="<?= h($credit_card->code); ?>" selected="selected">
											<?= h($credit_card->name); ?>
										</option>
									<?php else: ?>
										<option value="<?= h($credit_card->code); ?>">
											<?= h($credit_card->name); ?>
										</option>
									<?php endif; ?>
								<?php endforeach; ?>
							</select>
						</div>
					</div>

					<div class="col-md-4">
						<div class="form-group">
							<label for="large_service_area">大サービスエリア</label>
							<select class="form-control" name="large_service_area" id="large_service_area">
								<option value="">大サービスエリア</option>
								<?php foreach ($large_service_area->large_service_area as $large_service_area) : ?>
									<?php if ($large_service_area->code == filter_input(INPUT_GET, 'large_service_area')): ?>
										<option value="<?= h($large_service_area->code); ?>" selected="selected">
											<?= h($large_service_area->name); ?>
										</option>
									<?php else: ?>
										<option value="<?= h($large_service_area->code); ?>">
											<?= h($large_service_area->name); ?>
										</option>
									<?php endif; ?>
								<?php endforeach; ?>
							</select>
						</div>

						<div class="form-group">
							<label for="service_area">サービスエリア</label>
							<select class="form-control" name="service_area" id="service_area">
								<option value="">サービスエリア</option>
								<?php foreach ($service_area->service_area as $pref) : ?>
									<?php if ($pref->code == filter_input(INPUT_GET, 'service_area')): ?>
										<option value="<?= h($pref->code); ?>" selected="selected">
											<?= h($pref->name); ?>
										</option>
									<?php else: ?>
										<option value="<?= h($pref->code); ?>">
											<?= h($pref->name); ?>
										</option>
									<?php endif; ?>
								<?php endforeach; ?>
							</select>
						</div>
					</div>

					<div class="col-md-4">
						<div class="form-group">
							<label for="name_kana">店名 or ふりがな</label>
							<input class="form-control" type="text" name="name_kana" id="name_kana" value="<?= h(filter_input(INPUT_GET, 'name_kana')); ?>" />
						</div>

						<div class="form-group">
							<label for="keyword">フリーワード</label>
							<input class="form-control" type="text" name="keyword" id="keyword" value="<?= h(filter_input(INPUT_GET, 'keyword')); ?>" />
						</div>

					</div>
				</div>

				<div class="row">
					<div class="col-md-12">
						<div class="form-group">
							<button type="submit" class="btn btn-primary">検索</button>
						</div>
					</div>
				</div>
			</form>
			<?php if (is_object($restaurants)): ?>

				<p>検索結果 <?= h(number_format((int) $restaurants->results_available)); ?> 件</p>

				<?php if (isset($restaurants->error)): ?>

					<div>
						<?php foreach ($restaurants->error as $err) : ?>
							<h2><?= $err->code; ?></h2>
							<p><?= $err->message; ?></p>
						<?php endforeach; ?>
					</div>

				<?php else: ?>

					<?php $i = 0; ?>
					<?php foreach ($restaurants->shop as $rest) : ?>
						<?php if ($i % 2 == 0): ?>
							<div class="row">
							<?php endif; ?>
							<div class="col-md-6 shop">
								<div>
									<dl>
										<dt>ID</dt>
										<dd><?= h($rest->id); ?></dd>

										<dt>店名</dt>
										<dd><?= h($rest->name); ?></dd>

										<dt>ジャンル</dt>
										<dd><?= h($rest->genre->name); ?></dd>

										<dt>所在地</dt>
										<dd><?= h($rest->address); ?></dd>
									</dl>
									<div class="map" data-lat="<?= h($rest->lat); ?>" data-lng="<?= h($rest->lng); ?>">
									</div>
								</div>
							</div>
							<?php if ($i % 2 == 1 || count($restaurants->shop) - 1 == $i): ?>
							</div>
						<?php endif; ?>
						<?php $i++; ?>

					<?php endforeach; ?>

					<div class="row">
						<div class="col-md-12">
							<ul class="pagination pagination-sm no-margin">
								<?= Hpepper::pagination($restaurants->results_available); ?>
							</ul>
						</div>
					</div>

				<?php endif; ?>
			<?php endif; ?>

		</div>

		<script type="text/javascript" src="//www.google.com/jsapi"></script>
		<script type="text/javascript">
			var map;
			function initMap() {
				
				// map というクラスが付いている要素を複数取得
				// 同名IDはドキュメント内に複数設定できないため、クラスでアクセスする。
				// MAPがドキュメント内に一つだけ表示するなら、getElementById() を使えば良い。
				// @see https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByClassName
				var maps = document.getElementsByClassName('map');

				// 複数要素全てを処理する
				// @see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for
				for (var i = 0; i < maps.length; i++) {

					// それぞれの要素につけてれている data-* 属性から lat, lng を取得する
					// @see https://developer.mozilla.org/ja/docs/Web/API/Element/getAttribute
					var latlng = {
						// @see https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseFloat
						lat: parseFloat(maps[i].getAttribute('data-lat'))
						, lng: parseFloat(maps[i].getAttribute('data-lng'))
					};

					// MAPオブジェクトをそれぞれ生成する
					// @see https://developers.google.com/maps/documentation/javascript/tutorial?hl=ja
					map = new google.maps.Map(maps[i], {
						center: latlng,
						scrollwheel: false,
						zoom: 16
					});
					
					// 各MAPオブジェクトにマーカーを設定する
					// @see https://developers.google.com/maps/documentation/javascript/markers?hl=ja#add
					new google.maps.Marker({
						position: latlng,
						map: map
					});
				}

			}
		</script>
		<script src="//maps.googleapis.com/maps/api/js?key=GOOGLEMAP_API_KEY&callback=initMap&language=ja"></script>
	</body>
</html>
Hpepper.class.php
<?php

/**
 * Hpepper.class.php
 *
 * @since 2016/08/06
 */
class Hpepper
{

	/**
	 * アクセスキー
	 * @var string
	 */
	private static $token = 'APIKEY';

	/**
	 * 1ページに表示する件数
	 * @var int
	 */
	private static $rowCount = 10;

	/**
	 * API問い合わせ
	 * @param string $uri
	 * @param array $query
	 * @return object
	 */
	private static function request($uri, $query = array())
	{
		$query += array(
			'format' => 'xml'
			, 'key' => self::$token
		);
		
		// @see http://php.net/manual/ja/function.http-build-query.php
		$url = sprintf("%s?%s", $uri, http_build_query($query));
		$obj = simplexml_load_file($url);
		return $obj;
	}

	/**
	 * 予算リストを取得
	 * @return object
	 */
	public static function getBudget()
	{
		$uri = "http://webservice.recruit.co.jp/hotpepper/budget/v1/";
		return self::request($uri);
	}

	/**
	 * 大サービスエリア
	 * @return object
	 */
	public static function getLargeServiceArea()
	{
		$uri = "http://webservice.recruit.co.jp/hotpepper/large_service_area/v1/";
		return self::request($uri);
	}

	/**
	 * サービスエリアマスタAPI
	 * @return object
	 */
	public static function getServiceArea()
	{
		$uri = "https://webservice.recruit.co.jp/hotpepper/service_area/v1/";
		return self::request($uri);
	}

	/**
	 * 料理カテゴリ
	 * @return object
	 */
	public static function getFoodCategory()
	{
		$uri = "http://webservice.recruit.co.jp/hotpepper/food_category/v1/";
		return self::request($uri);
	}

	/**
	 * クレジットカードマスタAPI
	 * @return object
	 */
	public static function getCreditCard()
	{
		$uri = "http://webservice.recruit.co.jp/hotpepper/credit_card/v1/";
		return self::request($uri);
	}

	/**
	 * レストラン検索
	 * @return object
	 */
	public static function getRestaurants()
	{
		$uri = "http://webservice.recruit.co.jp/hotpepper/gourmet/v1/";
		$query = array(
			'count' => self::$rowCount
		);
		if (!is_null(filter_input_array(INPUT_GET))) {
			$query += filter_input_array(INPUT_GET);
		}
		return self::request($uri, $query);
	}

	/**
	 * ページネーション
	 * @param int $total
	 * @return string
	 */
	public static function pagination($total = 0)
	{
		if ($total == 0) {
			return;
		}
		$start = filter_input(INPUT_GET, 'start', FILTER_VALIDATE_INT);
		if ($start == 0) {
			$start = 1;
		}

		$html = '<li%s><a href="?%s">%s</a></li>';

		//現在の頁
		$curPage = ceil($start / self::$rowCount);
		$iStart = (0 < $curPage - 3) ? $curPage - 3 : 1;

		$pages = ceil($total / self::$rowCount);
		$iMax = ($iStart + 6 > $pages) ? $pages : $iStart + 6;

		$arr = array();
		$params = filter_input_array(INPUT_GET);

		// 先頭ページ
		if ($start != 1) {
			$params['start'] = 1;
			$query = http_build_query($params, '', '&amp;');
			$arr[] = sprintf($html, '', $query, '最初');
			$params['start'] = $start - self::$rowCount;
			$query = http_build_query($params, '', '&amp;');
			$arr[] = sprintf($html, '', $query, '前へ');
		}

		for ($i = $iStart; $i <= $iMax; $i++) {
			$params['start'] = ($i - 1) * self::$rowCount + 1;
			$class = ($params['start'] == $start) ? ' class="active"' : '';
			$query = http_build_query($params, '', '&amp;');
			$arr[] = sprintf($html, $class, $query, $i);
		}

		// 最終ページ
		$maxCount = ($pages - 1) * self::$rowCount + 1;
		if ($start < $maxCount) {
			$params['start'] = $start + self::$rowCount;
			$query = http_build_query($params, '', '&amp;');
			$arr[] = sprintf($html, '', $query, '次へ');
			$params['start'] = $maxCount;
			$query = http_build_query($params, '', '&amp;');
			$arr[] = sprintf($html, '', $query, '最終');
		}

		return implode(PHP_EOL, $arr);
	}

}

// PHPのみで構成されるファイルには終了タグ(?>)は不要。
// 終了タグの存在はかえってバグの元になる。

##スクリーンショット

hpapi.jlamp.net_2016-10-10_18-47-51.png

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?