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

Hello, FMCakeMix! チュートリアル / Authorsコントローラ、ビューの作成

まずはBooksコントローラと同じ要領で、次のアクションを作成する。

  • index: レコードの一覧画面を表示
  • add: レコードの登録画面を表示/登録処理
  • view: レコードの詳細画面を表示
  • edit: レコードの編集画面を表示、および編集処理
  • delete: レコードの削除処理。一覧(index)から実行。削除後、一覧に戻る
  • delete_all: 全レコードの削除処理。一覧(index)から実行。削除後、一覧に戻る

delete_allで使用するFileMakerスクリプトは作業レイアウトを指定していないので、どちらのコントローラから呼び出しても問題なく動作する。それではまずコントローラの実装から見ていこう。

authorsコントローラ記述例 - /app/controllers/authors_controller.php

<?php
class AuthorsController extends AppController
{
    var $name = 'Authors';

    function add()
    {

        if (!empty($this->data))
        {
            $this->Author->create();
            if ($this->Author->save($this->data))
            {
                $this->Session->setFlash(__('著者情報を保存しました', true));
                $this->redirect(array('action'=>'index'));
            }
            else
            {
                $this->Session->setFlash(__('著者情報の保存に失敗しました', true));
            }
        }
    }

    function index()
    {
        $this->paginate = array
        (
            'limit' => 5
        );

        $this->set('authors', $this->paginate());
    }

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

    function edit($id = null)
    {
        if (!$id && empty($this->data))
        {
            $this->Session->setFlash(__('不正なidです', true));
        }
        if (!empty($this->data))
        {
            if ($this->Author->save($this->data))
            {
                $this->Session->setFlash(__('著者情報を保存しました', true));
                $this->redirect(array('action'=>'index'));
            }
            else
            {
                $this->Session->setFlash(__('著者情報の保存に失敗しました', true));
            }
        }
        if (empty($this->data))
        {
            $this->data = $this->Author->read(null, $id);
        }
    }

    function delete($id=null)
    {
        $this->Author->find
        (
            'first',
            array
            (
                'conditions' => array
                (
                    'id' => $id 
                ),
                'recursive' => 0
            )
        );
        if ($this->Author->del())
        {
            $this->Session->setFlash(__('著者情報を削除しました', true));
            $this->redirect(array('action'=>'index'));
        }
        else
        {
            $this->Session->setFlash(__('著者情報の削除に失敗しました', true));
            $this->redirect(array('action'=>'view', 'id'=>$id));
        }
    }

    function delete_all()
    {
        $this->Author->find
        (
            'first',
            array
            (
                'conditions' => array
                (
                    '-script' => 'deleteAll'
                ),
                'recursive' => 0
            )
        );
        $this->Session->setFlash(__('著者情報を削除しました', true));
        $this->redirect(array('action'=>'index'));
    }

}
?>

つづいてdelete, delete_allを除く4アクションに対するビューを実装する。

authorsビュー記述例(一覧) - /app/view/authors/index.ctp

<h1>著者一覧</h1>

<p style="text-align: center">
<?php
    echo $paginator->counter
    (
        array
        (
            'format' => __('%page% / %pages% ページ,  <span class="foundCount">%count%</span>件中、%start% - %end% 件目を表示', true)
        )
    );
    echo '<br>';
    echo $paginator->prev('<< '.__('前のページ', true), array(), null, array('class'=>'disabled', 'tag' => 'span'));
    echo ' | ' . $paginator->numbers() . ' | ';
    echo $paginator->next(__('次のページ', true).' >>', array(), null, array('tag' => 'span', 'class' => 'disabled'));
?>
</p>

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

<p style="text-align: center">
<?php
    echo $paginator->counter
    (
        array
        (
            'format' => __('%page% / %pages% ページ,  <span class="foundCount">%count%</span>件中、%start% - %end% 件目を表示', true)
        )
    );
    echo '<br>';
    echo $paginator->prev('<< '.__('前のページ', true), array(), null, array('class'=>'disabled', 'tag' => 'span'));
    echo ' | ' . $paginator->numbers() . ' | ';
    echo $paginator->next(__('次のページ', true).' >>', array(), null, array('tag' => 'span', 'class' => 'disabled'));
?>
</p>

<ul>
    <li><?php echo $html->link('著者情報を登録する', array ( 'controller' => 'authors', 'action' => 'add') ); ?></li>
    <li><?php echo $html->link('著者情報を全削除', array ( 'controller' => 'authors', 'action' => 'delete_all' ), null, '著者情報をすべて削除します。よろしいですか?'); ?></li>
</ul>

authorsビュー記述例(登録) - /app/view/authors/add.ctp

<h1>著者登録</h1>

<?php
    echo $form->create('Author', array('action' => 'add'));
    echo $form->input('name',array('label'=>'著者名'));
    echo $form->end('著者情報を登録');
?>

<ul>
    <li><?php echo $html->link('著者情報一覧に戻る', array ( 'controller' => 'authors', 'action' => 'index' ) ); ?></li>
</ul>

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>

<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>

authorsビュー記述例(編集) - /app/view/authors/edit.ctp

<h1>著者編集</h1>

<?php
    echo $form->create('Author', array('action' => 'edit'));
    echo $form->input('name',array('label'=>'著者名'));
    echo $form->end('著者情報を編集');
?>

<ul>
    <li><?php echo $html->link('著者情報詳細に戻る', array ( 'controller' => 'authors', 'action' => 'view', 'id' => $this->data['Author']['id'] ) ); ?></li>
</ul>

AuthorsコントローラはBooksコントローラの実装をベースとし、用語やフィールド名を置きかえた。また、登録処理に成功した場合に一覧画面にリダイレクトするように修正をおこなっている。ビューについては登録画面(add.ctp)から一覧画面(/authors/index)に戻れるように$html->link()でリンクの追加をおこなった。

ひととおりの動作をWebブラウザで確認する。

著者一覧画面(authors/view)。著者レコードを一覧で表示する。ここでおこなえるアクションは「登録画面へ移動」「詳細画面へ移動」「全レコードを削除」の3つ

著者登録画面(authors/add)。こちらはただ名前を登録するのみ

レコード登録後は一覧画面へ移動

著者詳細画面(authors/view)。ここでおこなえるアクションは「一覧画面へ移動」「編集画面へ移動」「レコードを削除」の3つ。「この著者が書いた書籍」ポータルの実装法ものちのち紹介していこう

著者編集画面(authors/edit)も登録画面と同様

Hello, FMCakeMix! チュートリアル / 書籍と著者を関連付け

作成した「Book」「Author」2つのモデルを関連づける。まずは書籍登録画面で著者を選択できるようにしてみよう。

まずはじめに、値一覧機能の利用が必須になる。「最新FMCakeMixの動向を追う(2)」で紹介した内容を参考にしつつ、Bookモデル内に値一覧を使用することを明示する一文「var $returnValueLists = true;」をつけ加える。

bookモデル記述例 - /app/models/book.php

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

    // FMCakeMix specific attributes
    var $defaultLayout = 'books_list';
    var $returnValueLists = true;

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

}

つづいてFileMaker側で該当のフィールドに値一覧をセットしておく。関連する値一覧情報は次のとおり。

  • 値一覧名: Authors
  • 値一覧を設定したレイアウト名: books_list
  • 値一覧を設定したフィールド名: author_id

FileMakerで値一覧「Authors」を作成。authors内のid/nameを値一覧化

作成した値一覧をbookslistレイアウトのauthoridに設定

つづいてBooksコントローラ側で値一覧を取得する。

booksコントローラ記述例(登録) - /app/controllers/books_controller.php

    function add()
    {
        if (!empty($this->data))
        {
            $this->Book->create();
            if ($this->Book->save($this->data))
            {
                $this->Session->setFlash(__('書籍情報を保存しました', true));
            }
            else
            {
                $this->Session->setFlash(__('書籍情報の保存に失敗しました', true));
            }
        }
        $schema = array();
        $schema = $this->Book->schema();
        $this->set('schema', $schema);
    }

つづいてビューで、この値一覧をセレクトボックスとして表示する。

booksビュー記述例(登録) - /app/view/books/add.ctp

<h1>書籍登録</h1>

<?php
    echo $form->create('Book', array('action' => 'add'));
    echo $form->input('title',array('label'=>'書籍名'));
    echo $form->input('author_id',array('label'=>'著者','options' => $schema['author_id']['valuelist']));
    echo $form->end('書籍情報を登録');
?>

FileMakerの「ポップアップメニュー」に相当する<select><option>UIは、CakePHPの「$form->input('(フィールド名)', array('options' => (値一覧の配列)))」で実装する。FMCakeMixで値一覧を取得した場合は、キーが値一覧名ではなく"値一覧を設定しているフィールド名"になることに注意されたい。

それでは動作を確認してみよう。

修正後のレコード登録画面。著者にプルダウンが表示されている

authorsテーブル内のレコード分だけ著者をプルダウンで選択できるものの、このままでは表示が分かりづらい。またキーと実際のidも食い違っている

関連付けはできたものの、このままではユーザがどのidにどの著者が紐付いているかが分からず、使いやすいユーザインタフェースとは呼べない。FX.php/FMCakeMixで「値一覧の2番目のフィールドの値」を取得するにはFX.php/dbo_fmcakemix.phpを修正する必要がある。追って紹介していこう。