FMCakeMixのUser Guide.pdfを参考に、CakePHP x FileMakerでWebアプリの作成方法を紹介する。FX.phpに添付されているFileMakerファイルをベースに、Paginationを使った一覧画面の実装方法を。5回目よりCakePHP, FMCakeMixの規約、FileMakerデータベース、database.php、モデル、Booksの登録・一覧・詳細・編集・削除処理、そして値一覧を使ったひととおりの処理を紹介した。

前回はFX.phpとFMCakeMixでのポータル(関連)レコードの取扱いについての違いを紹介した。本チュートリアルの最後に、ポータルレコードを取り扱うためのモデル記述と注意点について取りあげよう。

Hello, FMCakeMix! チュートリアル / FMCakeMixで関連先レコードを取り扱うには

前回にFX.phpとFMCakeMixでポータルレコードの取得の違いについて紹介した。FMCakeMixでは事前にモデル間の関連付けをおこなっていないと、関連先のレコードを正しく取得することができない。まずはモデル間の関連づけをおこなおう。

今回はAuthorモデルとBookモデルをhasManyで関連付けをおこなう(Author hasMany Book)。コードの記述例は次のとおり。

Authorモデル記述例 - /app/model/author.php

<?php
class Author extends AppModel
{
    var $name = 'Author';
    var $useDbConfig = 'default';

    var $defaultLayout = 'authors_list';

    var $validate = array
    (   
        'name' => array
        (   
            'rule' => 'notEmpty',
            'message' => '著者名はかならず入力してください。'
        )   
    );  

    var $hasMany = array
    (   
        'Book' => array
        (   
            'className' => 'Book',
            // 'limit' => 2,
            'order' => array
            (   
                'title' => 'desc'
            ),  
        )   
    );  
}

hasMany関連の配列で指定可能なキーは次のとおり。(マニュアルより抜粋)

  • className: このモデルに関連に関連したモデルのクラス名。今回の関係はAuthor hasMany Bookのため、classNameキーは"Book"となる
  • foreignKey: 関連先のモデルにある外部キーの名前。デフォルトは「(モデル名)_id」。規約にしたがってフィールドが構成されている場合は指定する必要なし
  • conditions: 関連先モデルのレコードを絞り込むための検索条件を指定。この際フィールド名にはモデル名を付記しておいたほうがのぞましい
  • limit: レコードの最大取得数(-max)を指定
  • offset: 先頭から除外するレコード数(-skip)を取得

上記の例ではclassNameだけを指定している。いったん前回作成したfmcakemix_portal_testにアクセスし、配列を確認する。

array(2) {
  ["Author"]=>
  array(10) {
    ["-recid"]=>
    string(1) "4"
    ["-modid"]=>
    string(1) "0"
    ["id"]=>
    string(1) "4"
    ["created"]=>
    string(10) "1290488528"
    ["modified"]=>
    string(10) "1290488528"
    ["name"]=>
    string(15) "池波正太郎"
    ["books::id"]=>
    string(2) "10"
    ["books::created"]=>
    string(10) "1290488572"
    ["books::modified"]=>
    string(10) "1290488572"
    ["books::title"]=>
    string(15) "鬼平犯科帳"
  }
  ["Book"]=>
  array(7) {
    [0]=>
    array(7) {
      ["-recid"]=>
      string(2) "10"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "10"
      ["created"]=>
      string(10) "1290488572"
      ["modified"]=>
      string(10) "1290488572"
      ["title"]=>
      string(15) "鬼平犯科帳"
      ["author_id"]=>
      string(1) "4"
    }
    [1]=>
    array(7) {
      ["-recid"]=>
      string(2) "11"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "11"
      ["created"]=>
      string(10) "1290488579"
      ["modified"]=>
      string(10) "1290488579"
      ["title"]=>
      string(12) "剣客商売"
      ["author_id"]=>
      string(1) "4"
    }
    [2]=>
    array(7) {
      ["-recid"]=>
      string(2) "12"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "12"
      ["created"]=>
      string(10) "1290488587"
      ["modified"]=>
      string(10) "1290488587"
      ["title"]=>
      string(24) "仕掛人・藤枝梅安"
      ["author_id"]=>
      string(1) "4"
    }
    [3]=>
    array(7) {
      ["-recid"]=>
      string(2) "13"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "13"
      ["created"]=>
      string(10) "1290488594"
      ["modified"]=>
      string(10) "1290488594"
      ["title"]=>
      string(15) "真田太平記"
      ["author_id"]=>
      string(1) "4"
    }
    [4]=>
    array(7) {
      ["-recid"]=>
      string(2) "14"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "14"
      ["created"]=>
      string(10) "1290488648"
      ["modified"]=>
      string(10) "1290488648"
      ["title"]=>
      string(15) "田園の微風"
      ["author_id"]=>
      string(1) "4"
    }
    [5]=>
    array(7) {
      ["-recid"]=>
      string(2) "15"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "15"
      ["created"]=>
      string(10) "1290488671"
      ["modified"]=>
      string(10) "1290488671"
      ["title"]=>
      string(21) "江戸切絵図散歩"
      ["author_id"]=>
      string(1) "4"
    }
    [6]=>
    array(7) {
      ["-recid"]=>
      string(2) "16"
      ["-modid"]=>
      string(1) "0"
      ["id"]=>
      string(2) "16"
      ["created"]=>
      string(10) "1290488679"
      ["modified"]=>
      string(10) "1290488679"
      ["title"]=>
      string(12) "男の作法"
      ["author_id"]=>
      string(1) "4"
    }
  }
}

Author配列の中に著者情報が、Book配列の中に関連する書籍情報が複数格納できていることが確認できた。FX.phpではフィールド名がキーとなっているが、FMCakeMixではモデル->各レコード->各フィールド内容と構造がまとまっている。

では著者の詳細画面に、関連する書籍情報のポータルUIを実装してみよう。

authorsコントローラ記述例(詳細) - /app/controller/authors_controller.php

function view($id = null)
{
    $this->Author->id = $id;
    $this->Author->defaultLayout = 'author_view';
    $this->set('author', $this->Author->read());
}

authorsビュー記述例(詳細) - /app/view/authors/view.ctp

<h1>著者詳細</h1>

<table cellpadding="0" cellspacing="0">
    <tr>
        <th>
            Id
        </th>
        <td>
            <?php echo h($author['Author']['id']); ?>
        </td>
    </tr>
    <tr>
        <th>
            Name
        </th>
        <td>
            <?php echo h($author['Author']['name']); ?>
        </td>
    </tr>
    <tr>
        <th>
            Created
        </th>
        <td>
            <?php echo h(date('Y/m/d H:i:s', $author['Author']['created'])); ?>
        </td>
    </tr>
    <tr>
        <th>
            Modified
        </th>
        <td>
            <?php echo h(date('Y/m/d H:i:s', $author['Author']['modified'])); ?>
        </td>
    </tr>
</table>

<p>関連する書籍一覧</p>

<table cellpadding="0" cellspacing="0">
    <tr>
        <th>
            Id
        </th>
        <th>
            Title
        </th>
        <th>
            Created
        </th>
        <th>
            Modified
        </th>
    </tr>
    <?php
    $i = 0;
    foreach ($author['Book'] as $book)
    {
        ?>
        <tr>
            <td>
                <?php
                echo $html->link
                (
                    h($book['id']),
                    array
                    (
                        'controller' => 'books',
                        'action' => 'view',
                        'id' => $book['id']
                    )
                ); ?>
            </td>
            <td>
                <?php echo h($book['title']); ?>
            </td>
            <td>
                <?php echo h(date('Y/m/d H:i:s', $book['created'])); ?>
            </td>
            <td>
                <?php echo h(date('Y/m/d H:i:s', $book['modified'])); ?>
            </td>
        </tr> 
        <?php
    }
    ?>
</table>

<ul>
    <li><?php echo $html->link('著者情報を編集', array ( 'controller' => 'authors', 'action' => 'edit', 'id' => $author['Author']['id'] ) ); ?></li>
    <li><?php echo $html->link('著者情報を削除', array ( 'controller' => 'authors', 'action' => 'delete', 'id' => $author['Author']['id'] ), null, '「' . $author['Author']['title'] . '」を削除してもよろしいですか?'); ?></li>
    <li><?php echo $html->link('著者情報一覧', array ( 'controller' => 'authors', 'action' => 'index' ) ); ?></li>
</ul>

著者詳細画面の中央に、hasManyリレーションで取得した書籍情報の一覧を表示。IDをクリックして、書籍情報詳細画面に遷移できるようにコードを追加した。Webブラウザで表示を確認する。

著者に関連する書籍情報一覧を展開

1点注意しておきたい点として、モデル内の関連付けにおいて「limit」を指定しなかった場合、-maxにallが適用されてしまうことが挙げられる。関連先テーブルのレコードが大量にあった場合、FileMaker Serverにおおきな負荷がかかり、画面描画にも時間がかかる。モデル関連付けを試行錯誤している間は、limitに3や5など、少ない数字を指定しておいたほうが良いだろう。

Hello, FMCakeMix! チュートリアル / 関連先レコード取得時の、Web公開エンジンへのリクエストの違い

FMCakeMixでは関連先レコードを「指定したレイアウトに配置されているポータル」から取得するのではなく、「関連先モデルで指定されたレイアウト」から取得している。FX.phpのデバッグ機能を有効にし、FMCakeMixがどのようにWeb公開エンジンにアクセスしているかを確認してみよう。

  • Authorモデルのレコード取得URL: http://fmcakemix_user:fmcakemix_password@localhost:80/fmi/xml/FMPXMLRESULT.xml?-db=fmcakemix_db&-lay=authors\:_view&-max=1&id.op=eq&id=4&-find
  • Bookモデルのレコード取得URL: http://fmcakemix_user:fmcakemix_password@localhost:80/fmi/xml/FMPXMLRESULT.xml?-db=fmcakemix_db&-lay=books_list&-max=all&author_id.op=eq&author_id=4&-find
モデル アクセスしているレイアウト 検索条件 一度に取得する件数
Author authors_list idが4 1
Book books\_list author\_idが4 all

注目したいのはBookモデルのレコード取得時にアクセスしているレイアウト。books_listはBookモデル(/app/model/book.php)で指定しているレイアウト。上記の場合、authors_viewのポータルはPHP側でまったく使用されていないのにも関わらず、Web公開エンジンがレコードを取得する処理時間がかかってしまう。FMCakeMixではスクリプトなどを併用しない限り、レイアウトにポータルを配置する意味はほとんど皆無と言ってよいだろう。規模の大きいWebアプリケーションをFMCakeMixで開発中に、パフォーマンスの伸びがよくない場合は、まずはこの辺りから調査をしてみよう。

以上、各種マニュアルにのっとって14回にわたりFMCakeMixでの開発チュートリアルを紹介した。これでひととおりの基本動作をおさえたWebアプリケーションが完成した。何度も言うように、FMCakeMixは今日も開発が進むオープンソースソフトウェア。つねに最新の動向をチェックし、ソースコードレベルで動作を確認するようにしておきたいところだ。