PHP での MongoDB の使用

PHP Bookshelf チュートリアルのこのパートでは、MongoDB データベースで構造化データの作成、読み取り、更新、削除を行う方法について説明します。

このページは、複数のページで構成されるチュートリアルの一部です。最初からの説明や設定手順を確認するには、PHP Bookshelf アプリに移動してください。

Google Compute Engine での MongoDB の実行

まだ Mongo インスタンスをセットアップしていない場合、mLab を使用することで、Google Cloud Platform 上で動作するマネージド インスタンスを作成できます。Compute Engine で動作する非マネージド MongoDB インスタンスを使用している場合は、Bitnami の構成済みクリック デプロイ ソリューションをご確認ください。

最適な結果を得るため、必ず Google Cloud Platform 上で MongoDB インスタンスをホストし、アプリと同じリージョンに配置してください。

デフォルトでは、MongoDB での通信にはポート 27017 が使用されます。MongoDB インスタンスを設定したら、このポートとの間で送受信されるトラフィックを許可するようにファイアウォール ルールを設定することが必要になる場合があります。インスタンスが Google Cloud Platform で実行されている場合の手順については、ファイアウォール ルールの使用をご覧ください。

PHP 用の MongoDB をインストールして有効にする

このアプリをローカルで実行しながら MongoDB に接続するには、次の手順で PHP MongoDB 拡張機能をインストールします。Linux を使用している場合には、PECL もインストールする必要があります。

この作業が完了したら、php.ini で拡張機能を有効にします。

Linux / Mac OS X

echo "extension=mongodb.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`

Windows

php.ini ファイルに次の行を追加します。

extension=php_mongodb.dll

これで拡張機能がインストールされました。次に、MongoDB ライブラリを Composer に追加する必要があります。

composer require "mongodb/mongodb:^1.0.0"

設定の構成

  1. getting-started-php/2-structured-data ディレクトリに移動して、settings.yml.dist ファイルをコピーします。

    cp config/settings.yml.dist config/settings.yml
    
  2. 編集のため config/settings.yml を開きます。

  3. YOUR_PROJECT_ID を実際のプロジェクト ID に置き換えます。

  4. bookshelf_backend の値を mongodb に設定します。

  5. mongo_urlmongo_databasemongo_collection の値を MongoDB インスタンスに適切な値に設定します。次に例を示します。

    mongo_url: mongodb://104.197.3.232:27017
    mongo_database: getting_started_php
    mongo_collection: books
    
  6. settings.yml を保存して閉じます。

依存関係のインストール

2-structured-data ディレクトリで、次のコマンドを入力します。

composer install

ローカルマシンでのアプリの実行

  1. ローカル ウェブサーバーを起動します。

    php -S localhost:8000 -t web
    
  2. ウェブブラウザで、次のアドレスを入力します。

    http://localhost:8000

これで、このアプリのウェブページを表示し、書籍の追加、編集、削除を行うことができます。

App Engine フレキシブル環境へのアプリのデプロイ

  1. サンプルアプリをデプロイします。

    gcloud app deploy
    
  2. ウェブブラウザで、次のアドレスを入力します。[YOUR_PROJECT_ID] は実際のプロジェクト ID で置き換えます。

    https://[YOUR_PROJECT_ID].appspot.com
    

    アプリを更新する場合は、最初にデプロイしたときと同じコマンドを使って、更新バージョンをデプロイできます。デプロイを行うと、アプリの新しいバージョンが作成され、それがデフォルトのバージョンに設定されます。古いバージョンはそのまま残り、関連付けられた VM インスタンスも同様に残ります。すべてのアプリ バージョンと VM インスタンスが課金対象のリソースとなるのでご注意ください。

    アプリのデフォルト以外のバージョンを削除することで、コストを削減できます。

    アプリのバージョンを削除する手順は次のとおりです。

    1. GCP Console の [App Engine のバージョン] ページに移動します。

      [バージョン] ページに移動

    2. 削除したい、デフォルト以外のアプリのバージョンの横にあるチェックボックスをクリックします。
    3. ページ上部にある [削除] ボタンをクリックし、アプリのバージョンを削除します。

    課金対象のリソースをクリーンアップする方法の詳細については、このチュートリアルの最後のステップにあるクリーンアップ セクションを参照してください。

    アプリケーションの構造

    次の図は、サンプル アプリケーション コンポーネントを相互に接続する方法を示しています。

    Bookshelf アプリのデプロイ プロセスと構造

    コードの説明

    以前のステップで settings.yml を編集して、bookshelf_backend の値を mongodb に設定しました。これにより、src/DataModel/MongoDb.php で定義した MongoDb クラスが読み込まれます。MongoDb クラスは MongoDB API をラップし、MongoDB データベースに書籍情報を格納します。

    controllers.php にある次のコードが GET '/books' ルートのハンドラを定義し、登録しています。$model 変数は MongoDb クラスのインスタンスです。$model->listBooks メソッドが、書籍の配列とカーソルを含む配列を戻します。その後、list.html.twig テンプレートに従って Twig テンプレート エンジンが書籍のリストを生成します。

    $app->get('/books/', function (Request $request) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
        $token = $request->query->get('page_token');
        $bookList = $model->listBooks($app['bookshelf.page_size'], $token);
    
        return $twig->render('list.html.twig', array(
            'books' => $bookList['books'],
            'next_page_token' => $bookList['cursor'],
        ));
    });

    次の Twig テンプレートは、Cloud SQL データベースから取得した書籍のリストを生成するテンプレートです。このテンプレートは books という名前の配列変数を受信します。配列内の書籍ごとに、タイトルと著者名を表示します。また、テンプレートが受信する next_page_token 変数は、[More] ボタンを表示するかどうかを決定します。

    {% for book in books %}
    <div class="media">
      <a href="/books/{{book.id}}">
        <div class="media-left">
          <img src="http://placekitten.com/g/128/192">
        </div>
        <div class="media-body">
          <h4>{{book.title}}</h4>
          <p>{{book.author}}</p>
        </div>
      </a>
    </div>
    {% else %}
    <p>No books found</p>
    {% endfor %}

    このコードは、GET '/books/{id}' ルートのハンドラを定義して登録します。{id} は、個々の書籍の ID です。ハンドラは、$model->read メソッドを呼び出し、指定された書籍の情報を Cloud SQL から取得します。Twig テンプレート エンジンは、view.html.twig テンプレートに従って書籍の情報を表示します。

    $app->get('/books/{id}', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if (!$book) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('view.html.twig', array('book' => $book));
    });

    view.html.twig テンプレートは、book という名前の変数を受信し、書籍のタイトル、出版日、著者名、説明を表示します。

    <div class="media">
      <div class="media-body">
        <h4 class="book-title">
          {{book.title}}
          <small>{{book.published_date}}</small>
        </h4>
        <h5 class="book-author">By {{book.author|default('Unknown', True)}}</h5>
        <p class="book-description">{{book.description}}</p>
      </div>
    </div>

    ユーザーが [Add book] をクリックすると、GET /books/add のハンドラは、タイトル、著者名などの書籍情報を入力するフォームを表示します。ユーザーが [Save] をクリックすると、POST /books/add のハンドラがリクエストから新しい書籍情報を取得し、$model->create を呼び出して書籍を Cloud SQL に格納します。

    $app->get('/books/add', function () use ($app) {
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('form.html.twig', array(
            'action' => 'Add',
            'book' => array(),
        ));
    });
    
    $app->post('/books/add', function (Request $request) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $request->request->all();
        $id = $model->create($book);
    
        return $app->redirect("/books/$id");
    });

    次のテンプレートは、書籍情報の入力用フォームです。

    {% extends "base.html.twig" %}
    
    {% block content %}
    <h3>{{action}} book</h3>
    
    <form method="POST" enctype="multipart/form-data">
    
      <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="author">Author</label>
        <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="published_date">Date Published</label>
        <input type="text" name="published_date" id="published_date" value="{{book.published_date}}" class="form-control"/>
      </div>
    
      <div class="form-group">
        <label for="description">Description</label>
        <textarea name="description" id="description" class="form-control">{{book.description}}</textarea>
      </div>
    
      <button id="submit" type="submit" class="btn btn-success">Save</button>
    </form>
    
    {% endblock %}

    このサンプルコードには、書籍情報を個別に編集または削除するハンドラも追加されています。

    $app->get('/books/{id}/edit', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if (!$book) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        /** @var Twig_Environment $twig */
        $twig = $app['twig'];
    
        return $twig->render('form.html.twig', array(
            'action' => 'Edit',
            'book' => $book,
        ));
    });
    
    $app->post('/books/{id}/edit', function (Request $request, $id) use ($app) {
        $book = $request->request->all();
        $book['id'] = $id;
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        if (!$model->read($id)) {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
        if ($model->update($book)) {
            return $app->redirect("/books/$id");
        }
    
        return new Response('Could not update book');
    });
    $app->post('/books/{id}/delete', function ($id) use ($app) {
        /** @var DataModelInterface $model */
        $model = $app['bookshelf.model'];
        $book = $model->read($id);
        if ($book) {
            $model->delete($id);
    
            return $app->redirect('/books/', Response::HTTP_SEE_OTHER);
        }
    
        return new Response('', Response::HTTP_NOT_FOUND);
    });
このページは役立ちましたか?評価をお願いいたします。