目次


クラウド内で気象情報追跡アプリケーションを構築する

第 1 回

PHP、jQuery Mobile、そして IBM Insights for Weather を使えば簡単なことです

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: クラウド内で気象情報追跡アプリケーションを構築する

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:クラウド内で気象情報追跡アプリケーションを構築する

このシリーズの続きに乞うご期待。

翌日の天気予報をチェックするために、夜のニュース番組にチャンネルを合わせていた時代を覚えていますか?そうした日々はもう遠い昔の話であって、今では気象情報にフォーカスしたアプリケーションや API がいくらでもあるため、それらを利用すれば、リアルタイムで更新される気象情報をインターネットで入手することができます。モバイル・アプリや Web アプリケーションに気象情報を組み込もうとしている開発者にとって、今は何不自由ない時代にいるのです。

ではどのように始めればよいのでしょう?そこでこのチュートリアルが役立ちます。この第 1 回では、ベースとなるアプリケーションを作成してオンライン・サービスから世界の都市の緯度と経度の座標を取得して保管する方法を紹介します。続く第 2 回では、IBM が提供している新しい Insights for Weather サービスを紹介するほか、世界の都市を 5 つ選んでそれらの気象情報を追跡するために、第 1 回で取得した都市の情報を使用する方法、そして完成したアプリケーションを IBM Bluemix 上でホストする方法についても取り上げます。

サンプル・アプリを実行するサンプル・アプリのコードを入手する

アプリケーションを作成するために必要となるもの

このチュートリアルで説明するサンプル・アプリケーションでは、気象情報を追跡したい都市を、ユーザーが最大 5 つまで選択することができます。選択された各都市について、アプリケーションは現在の気温と気象状況の情報を取得し、その情報をモバイル用に最適化されたビューに表示します。このビューは、スマートフォンで使用するにもデスクトップ・コンピューターで使用するにも適したものになっています。さらに、ユーザーは各都市の向こう 7 日間の天気予報をはじめとし、Insights for Weather から提供されるすべての気象情報にアクセスすることもできます。

クライアント・サイドでは、jQuery Mobile を使用して、アプリケーションのモバイル対応ユーザー・インターフェースを作成します。サーバー上では、アプリケーションのフローを管理するために Silex という PHP マイクロフレームワークを使用し、ページ・テンプレートをレンダリングするために Twig テンプレート・エンジンを使用し、選択された都市のリストを保管するために MongoDB を使用します。このサンプル・アプリケーションは最終的に IBM Bluemix 上にホストされ、気象データを取得できるように Insights for Weather サービスに接続し、都市の情報を取得できるように GeoNames サービスに接続します。

このアプリケーションで使用する技術は数多くあるため、読者の皆さんには以下のものが必要になります。

  • jQuery MobilePHP の基礎知識。
  • Apache (mod_rewrite が実装され、.htaccess ファイルに対応したもの) または nginx がインストールされたローカル PHP 開発環境。
  • データベース、ユーザー、およびパスワードを構成済みのローカルまたはリモートの MongoDB デプロイメント。MongoDB の無料または有料のデプロイメントを取得するには、MongoLab アカウントに登録してください。
  • Bluemix のアカウント (無料のトライアル・アカウントを登録するか、アカウントを登録済みの場合は、そのアカウントで Bluemix にログインします)。
  • Web サービスへのアクセスが有効にされた、無料の GeoNames アカウント。
  • Composer (PHP 依存関係マネージャー)
  • CloudFoundry コマンド・ライン・ツール
  • テキスト・エディターまたは IDE

このチュートリアルでは、GeoNames API と IBM Bluemix を利用して、クラウド内で使用できる単純な気象情報モニターを作成する方法を紹介します。

: GeoNames Web サービスを利用するアプリケーションは例外なく、GeoNames の利用規約に従わなければなりません。同様に、IBM Insights for Weather サービスを利用するアプリケーションも、Bluemix の資料に記載されているこのサービスの利用条件に従わなければなりません。プロジェクトを開始する前に利用条件に書かれている要求事項を読んで、アプリケーションがそれらの要求事項を満たしていることを確認してください。

ステップ 1. 必要最低限のアプリケーションを作成する

最初のステップは、Silex PHP マイクロフレームワークと Twig テンプレート・エンジンを使用して、基本的なアプリケーションを初期化することです。

  1. Composer という PHP 依存関係マネージャーを使用して、Silex PHP マイクロフレームワークと Twig テンプレート・エンジンをダウンロードします。以下の Composer 構成ファイルを $APP_ROOT/composer.json に保存します (ここで、$APP_ROOT はプロジェクト・ディレクトリーです)。
    {
        "require": {
            "silex/silex": "*",
            "twig/twig": "*"   
        },
        "minimum-stability": "dev",
        "prefer-stable": true
    }
  2. 以下のコマンドで、Composer を使用して Silex と Twig をインストールします。
    shell> php composer.phar install
  3. アプリケーションのメイン制御スクリプトをセットアップします。以下に示すスクリプトは、Silex フレームワークをロードして、Silex アプリケーションを初期化します。このスクリプトには、アプリケーションのルートそれぞれのコールバックも含まれています。これらのコールバックには、受信されるリクエストとルートが一致したときに実行されるコードが定義されています。サンプル・アプリケーションでサポートしなければならない処理は、都市のリスト表示、追加、削除、検索なので、URL ルートとしては、以下に示すように /index/add/delete、および /search を定義します。このスクリプトは $APP_ROOT/index.php という名前で保存する必要があることに注意してください。
    <?php
    // use Composer autoloader
    require 'vendor/autoload.php';
    require 'config.php';
    
    // load classes
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Silex\Application;
    
    // initialize Silex application
    $app = new Application();
    
    // load configuration from file
    $app->config = $config;
    
    // register Twig template provider
    $app->register(new Silex\Provider\TwigServiceProvider(), array(
      'twig.path' => __DIR__.'/views',
    ));
    
    // register URL generator
    $app->register(new Silex\Provider\UrlGeneratorServiceProvider());
    
    // index page handlers
    $app->get('/', function () use ($app) {
      return $app->redirect($app["url_generator"]->generate('index'));
    });
    
    $app->get('/index', function () use ($app, $db) {
        // CODE
    })
    ->bind('index');
    
    // search form
    $app->get('/search', function () use ($app) {
        // CODE
    })
    ->bind('search');
    
    // search processor
    $app->post('/search', function (Request $request) use ($app) {
        // CODE
    });
    
    // handler to add city to database
    $app->get('/add/{gid}', function ($gid) use ($app, $db) {
        // CODE
    })
    ->bind('add');
    
    // handler to remove city from database
    $app->get('/delete/{id}', function ($id) use ($app, $db) {
        // CODE
    })
    ->bind('delete');
    
    // error page handler
    $app->error(function (\Exception $e, $code) use ($app) {
        // CODE
    });
    
    $app->run();
  4. アプリケーションがレンダリングするさまざまなビューに共通して使用できる単純なページ・テンプレートを作成します。以下に、一例を示します。
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>    
      </head>
      <body>
    
        <div data-role="page">
    
          <div data-role="header">
            <h1>Weather Tracker</h1>
          </div>
    
          <div data-role="content">       
          </div>
    
          <div data-role="footer">
          </div>
    
        </div>
          
      </body>
    </html>

このページは、Google CDN (Content Delivery Network) から jQuery と jQuery Mobile をセットアップして、基本的な jQuery Mobile ページを定義します。上記のコードを見るとわかるように、ページには現在、ヘッダー、コンテンツ・エリア、フッターが含まれています。このチュートリアルを進めていくと、このページ・テンプレートに各ビューのコンテンツが取り込まれていきます。

ステップ 2. 場所検索機能を実装する

IBM Insights for Weather サービスでは、ユーザーが気象情報を必要とする場所の緯度と経度の値を、このサービスの API に対する必須入力として要求しています。ただし、モニター対象とするすべての場所の緯度と経度の値をユーザーが把握していることを期待するのは妥当ではないため、このアプリケーションでは、場所名をそれぞれに対応する地理座標にマッピングする手段を用意する必要があります。

そのようなマッピング機能を提供するのが、GeoNames 地理データベースです。このデータベースには、800 万を超える場所のデータが格納されており、地理座標のほかに、人口、地物に関する情報が揃っています。GeoNames 地理データベースには GeoNames Web サービスを利用してアクセスすることができるため、GeoNames のデータは簡単に PHP アプリケーションに取り込むことができます。

  1. GeoNames を利用するために、無料の GeoNames アカウントにサインアップし、そのアカウントで Web サービスにアクセスできるようにします。これにより、http://api.geonames.org/search?q=london&maxRows=20&username=USERNAME のような URL を指定してリクエストを送信することで、GeoNames の API にアクセスできるようになります。このようなリクエストによって、検索クエリーにマッチする一連の場所名が生成されます (以下のコードを参照)。
  2. それぞれの結果には、一意の GeoNames ID と、緯度、経度、都市名、国名および国コードが含まれていることに注目してください。こうした情報を使用するように、アプリケーションの検索インターフェースを実装するのは簡単です。
    <?php
    // search form
    $app->get('/search', function () use ($app) {
      return $app['twig']->render('search.twig', array());
    })
    ->bind('search');
    
    // search processor
    $app->post('/search', function (Request $request) use ($app) {
      // search for location string against Geonames database
      // for each result, store location name, country and Geonames ID
      $query = urlencode(strip_tags($request->get('query')));
      $sxml = simplexml_load_file('http://api.geonames.org/search?q=' . $query . '&maxRows=20&username=' . $app->config['geonames_uid']);
      if ($sxml === FALSE) {
        throw new Exception("Could not connect to Geonames API.");  
      }
      $data = array();
      foreach ($sxml->geoname as $g) {
        $data[] = array(
          'gid' => (int)$g->geonameId,
          'location' => (string)$g->name,
          'country' => (string)$g->countryName,
        );
      }
      return $app['twig']->render('search.twig', array('data' => $data, 'query' => urldecode($query)));
    });
  3. 最初の GET ハンドラーは、テキスト入力フィールドが含まれる単純な検索フォームをレンダリングします。ユーザーがこのフォームを送信すると、2 番目の POST ハンドラーが以下の処理を行います。
    • 検索クエリーを GeoNames Web サービス呼び出しに組み込みます。
    • 結果を繰り返し処理します。
    • 対象とする場所の GeoNames ID、場所名、国名からなる配列を作成します。

    この配列が検索テンプレートに渡されて、そこにリストとして表示されます。検索フォームと結果テンプレートを処理するコードは以下のとおりです。このコードは、$APP_ROOT/views/search.twig にあります。

          <div data-role="content">       
            <div id="search">
              <h2 class="ui-bar ui-bar-a">Location Search</h2>
              <div class="ui-body">
                <form method="post" data-ajax="false" action="{{ app.url_generator.generate('search') }}">
                  <input type="search" name="query" value="{{ query}}" />
                  <input type="submit" name="submit" value="Search" />
                </form>
              </div>
              {% if data %}
              <h2 class="ui-bar ui-bar-a">Results</h2>
              <div class="ui-body">
                <ul data-role="listview" data-split-icon="plus" data-split-theme="d">          
                {% for item in data %}
                  <li>
                      <a>{{ item.location }}, {{ item.country }}</a>
                      <a href="{{ app.url_generator.generate('add', {'gid': item.gid}) }}" data-ajax="false">Add</a>                 
                  </li>
                {% endfor %}
                </ul>
              </div>
              {% endif %}
            </div>
          </div>

    フォームがどのような表示になるのか、その一例を以下に示します。

ステップ 3. 選択された場所をデータベースに追加する

先に進む前に、$APP_ROOT/config.php ファイルから提供される情報を使用して MongoDB データベース接続を初期化しておく必要があります。この処理を行うコード・フラグメントを以下に示します。

<?php
// configure MongoDB client
$dbn = substr(parse_url($app->config['db_uri'], PHP_URL_PATH), 1);
$mongo = new MongoClient($app->config['db_uri'], array("connectTimeoutMS" => 30000));
$db = $mongo->selectDb($dbn);

前のステップのテンプレートを見るとわかるように、検索結果の場所ごとに追加ボタンが組み込まれます。このボタンは /add ルートにハイパーリンクされていて、該当する場所の一意の GeoNames ID を /add ルート・ハンドラーに渡します。次はこのハンドラーについて見て行きましょう。

// handler to add location to database
$app->get('/add/{gid}', function ($gid) use ($app, $db) {
  // use Geonames ID to get location latitude/longitude from Geonames service
  // connect to MongoDB and save in database
  $collection = $db->locations;
  $query = (int)urlencode(strip_tags($gid));
  $sxml = simplexml_load_file('http://api.geonames.org/get?geonameId=' . $query . '&username=' . $app->config['geonames_uid']);
  if ($sxml === FALSE) {
    throw new Exception("Could not connect to Geonames API.");  
  }
  $location = new stdClass;
  $location->gid = trim(strip_tags($sxml->geonameId));
  $location->location = trim(strip_tags($sxml->name));
  $location->country = trim(strip_tags($sxml->countryCode));
  $location->lat = trim(strip_tags($sxml->lat));
  $location->lng = trim(strip_tags($sxml->lng));
  $cursor = iterator_to_array($collection->find());
  // disallow if 5 locations already exist
  if (count($cursor) >= 5) {
    throw new Exception("A maximum of 5 locations are supported. Please remove a location and try again.");
  }
  // disallow if selected location already exists
  foreach ($cursor as $key => $value) {
    if ($value['gid'] == $location->gid) {
      throw new Exception("The selected location already exists in the location list.");  
    }
  }
  $collection->save($location);
  return $app->redirect($app["url_generator"]->generate('index'));
})
->bind('add');

/add ルート・ハンドラーは GeoNames ID をルート・パラメーターとして受け取った後、GeoNames Web サービスに接続します。この場合の接続には /get API エンドポイントが使用され、選択された場所に関してのみ詳細情報が取得されます。Web サービスから取得した情報は、選択された場所の GeoNames ID (gid)、場所名 (location)、国名 (country)、緯度 (lat)、経度 (lng) のそれぞれに対応するプロパティーが設定された PHP オブジェクトに変換されます。このオブジェクトを MongoDB データベース内の locations コレクションに保存するために、MongoDB 接続オブジェクトが使用されます。

/add ルート・ハンドラーでは、選択された場所をデータベースに保存する前に、さらに 2 つのチェックを行ってもいることに注目してください。具体的には、選択された場所がすでにデータベースに存在していないことをチェックし、次に、データベースに保存される場所の数が 5 つを超えないことをチェックします。最初のチェックを行う理由は言うまでもなく明らかです。2 番目のチェックを行う理由は、無料版の Insights for Weather サービスに設けられている制限にあります。無料版では、限られた数の API 呼び出しだけが許可されていて、個々の API 呼び出しは緯度/経度の各ペアに対して行わなければなりません。従って、アプリケーションがサービス割り当て量の範囲を超えないよう、場所の数を 5 つに制限しているというわけです。さらに、こうすることにより、必要となるリクエストの数が少なくなるため、必要なすべての気象データを取得するまでの時間が短縮されます。

まとめ

この第 1 回では、ベースとなるアプリケーションを作成して、オンライン・サービスから世界の都市の緯度と経度の座標を取得して保管する方法を紹介しました。第 2 回では、Bluemix の新しい IBM Insights for Weather サービスを紹介するとともに、世界の都市を 5 つ選んでそれらの気象情報を追跡するために、第 1 回で取得した都市の情報を使用する方法と、完成したアプリケーションを IBM Bluemix 上でホストする方法についても取り上げます。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing, Mobile development
ArticleID=1030953
ArticleTitle=クラウド内で気象情報追跡アプリケーションを構築する: 第 1 回
publish-date=05192016