詳細画面の実装

詳細画面の実装方法はおおきくわけて、二通りの方法がある。

  • レコードIDをもとに、レコード情報を取得
  • 一覧画面で指定する検索条件とまったくおなじコードを使い、一度に取得する件数と-skipを調節、レコード情報を取得

それぞれメリットとデメリットが存在する。代表的なメリットとデメリットを挙げてみよう。

レコードIDを使用して取得する場合

--メリット

  • 実装が比較的容易
  • 記述する処理自体がすくないため、別機能の実装やトラブル時の原因切り分けをおこないやすい

--デメリット

  • 指定したレコードの前後にあるレコード情報を取得することができない。ページャの実装が困難

一度に取得する件数と-skipを調節して取得する場合

--メリット

  • ページャの実装が可能。(前後のレコード情報はskipを使用すれば取得できるため)

--デメリット

  • レコードID指定ではなく条件を入力したうえでの検索をおこなうため、レコードIDを使用して取得する方法と比較するとパフォーマンスが落ちる場合がある
  • 遷移元/遷移先でおこなう処理や、つねに「どのようなクエリがFileMakerに渡されるか」といった情報を把握しながら実装をおこなう必要がある

FileMakerアプリケーション上では「できて当たり前」の"詳細画面上での前レコード、次レコードへ移動"といったようなページャだが、Webアプリケーションではなかなか表現しづらい点のひとつだ。FileMakerを使用したWebアプリの開発に慣れないうちや、実装するべき機能が確定しきっていないうちはレコードIDを使用した方法を採用し、実装するべき仕様・機能の全体を見とおせている場合や、詳細画面でどうしてもページャが欲しい場合は一度に取得する件数と-skipを調節して取得する方法を採用するのがいいだろう。

一覧画面: ファイル - fm_list.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

// レコードIDの取得用関数
function getRecid($str)
{
    $tmp = explode('.',$str);
    return $tmp[0];
}

// 修正IDの取得用関数
function getModid($str)
{
    $tmp = explode('.',$str);
    return $tmp[1];
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_list', 5);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$data->AddSortParam('f_serial', 'descend');
$data->FMSkipRecords($_GET['skip']);

$dataSet = $data->FMFind();

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ一覧</title>
</head>

<body>

    <p>
        該当: <?php echo number_format($dataSet['foundCount']); ?>件、
        <?php echo h(number_format($_GET['skip']+1)); ?>件目から <?php echo h($_GET['skip']+count($dataSet['data']) )?>件目を表示中
    </p>

    <table border="1">
        <thead>
            <tr>
                <th>
                    &nbsp;
                </th>
                <th>
                    シリアル
                </th>
                <th>
                    氏名
                </th>
                <th>
                    FileMakerの<br>Webはいつから
                </th>
                <th>
                    使用したことがある<br>バージョン
                </th>
            </tr>
        </thead>
        <tbody>
        <?php
        $n = 0;
        foreach ( $dataSet['data'] as $key => $value )
        {
        ?>
            <tr>
                <td align="center">
                    <a href="./fm_detail_recid.php?recid=<?php echo getRecId($key); ?>">詳細(recid)</a>
                    <br>
                    <a href="./fm_detail_skip.php?skip=<?php echo (int)h($_GET['skip']) + $n ; ?>">詳細(skip)</a>
                </td>
                <td>
                    <?php
                    echo h($value['f_serial'][0]);
                    ?>
                </td>
                <td>
                    <?php
                    echo h($value['f_name'][0]);
                    ?>
                </td>
                <td>
                    <?php
                    echo h($value['f_history'][0]);
                    ?>
                </td>
                <td>
                    <?php
                    echo h(str_replace("\n", ', ', $value['f_useVersion'][0]));
                    ?>
                </td>
            </tr>
        <?php
            $n++;
        }
        ?>
        </tbody>
    </table>

    <p>
            <?php 
        if (!empty($dataSet['linkPrevious']))
        {
            ?>
            <a href="<?php echo h($dataSet['linkPrevious']); ?>">前のページへ</a>
            <?php
        }
        else
        {
            ?>
            前のページへ
            <?php
        }
        ?>
        / 
        <?php 
        if (!empty($dataSet['linkNext']))
        {
            ?>
            <a href="<?php echo h($dataSet['linkNext']); ?>">次のページへ</a>
            <?php
        }
        else
        {
            ?>
            次のページへ
            <?php
        }
        ?>
    </p>

</body>

</html>

比較用に一覧画面から2つの詳細画面へのリンクを用意した。詳細画面(1)へは該当行のレコードIDを、詳細画面(2)へは先頭からのskip数を計算して指定している。レコードIDについてだが、レコードIDと修正IDはそれぞれ「.」で連結したものが配列のキーとして格納される。ここでは「.」つきのキーを渡すとレコードID・修正IDをそれぞれ返す関数を作成して利用している。

比較用に一覧画面から2つの詳細画面へのリンクを用意した

詳細画面(1) - レコードIDを使用した実装方法: ファイル - fm_detail_recid.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

// レコードIDの取得用関数
function getRecid($str)
{
    $tmp = explode('.',$str);
    return $tmp[0];
}

// 修正IDの取得用関数
function getModid($str)
{
    $tmp = explode('.',$str);
    return $tmp[1];
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail', 1);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$data->SetRecordID($_GET['recid']);

$dataSet = $data->FMFind();

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ詳細</title>
</head>

<body>

    <p>
        レコードID: <?php echo h($_GET['recid']); ?> の詳細情報を表示中
    </p>

    <?php
    foreach ( $dataSet['data'] as $key => $value )
    {
        $recid = getRecId($key);
        $modid = getModId($key);
    ?>
    <table border="1" width="500px">
        <tr>
            <th width="30%">
                シリアル
            </th>
            <td width="70%">
                <?php
                echo h($value['f_serial'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                氏名
            </th>
            <td>
                <?php
                echo h($value['f_name'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                年齢
            </th>
            <td align="right">
                <?php
                echo h($value['f_age'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                FileMakerの<br>Webはいつから
            </th>
            <td>
                <?php
                echo h($value['f_history'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                使用したことがある<br>バージョン
            </th>
            <td>
                <?php
                echo h(str_replace("\n", ', ', $value['f_useVersion'][0]));
                ?>
            </td>
        </tr>
        <tr>
            <th>開発に使用<br>しているOS</th>
            <td>
            <?php
            echo h(str_replace("\n", ', ', $value['f_useOS'][0]));
            ?>
            </td>
        </tr>
    </table>
    <?php
    }
    ?>

    <ul>
        <li><a href="./fm_edit.php?recid=<?php echo h($recid); ?>">このレコードを編集する</a></li>
        <li><a href="./fm_delete.php?recid=<?php echo h($recid); ?>">このレコードを削除する</a></li>
        <li><a href="./fm_list.php">一覧画面へ移動する</a></li>
        </ul>

</body>

</html>

一覧画面からレコードIDを指定してジャンプし、$_GET['recid']で引数としてわたされたレコードIDを取得。SetRecordIDでレコードIDを指定してレコードを取得している。

レコードIDのみで取得した場合の詳細画面。前後のレコード情報を取得することができないためページャの実装がむずかしいが、シンプルな動作だけに機能の追加やデバッグがしやすい

詳細画面(2) - skipを調節した実装方法: ファイル - fm_detail_skip.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

// レコードIDの取得用関数
function getRecid($str)
{
    $tmp = explode('.',$str);
    return $tmp[0];
}

// 修正IDの取得用関数
function getModid($str)
{
    $tmp = explode('.',$str);
    return $tmp[1];
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail', 1);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

// 検索条件・ソート条件を fm_list.php と同一にする
$data->AddSortParam('f_serial', 'descend');
$data->FMSkipRecords($_GET['skip']);

$dataSet = $data->FMFind();

?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ詳細</title>
</head>

<body>

    <p>
        先頭から<?php echo h(number_format($_GET['skip']+1)); ?>件目の詳細情報を表示中
    </p>

    <?php
    foreach ( $dataSet['data'] as $key => $value )
    {
        $recid = getRecId($key);
        $modid = getModId($key);
    ?>
    <table border="1" width="500px">
        <tr>
            <th width="30%">
                シリアル
            </th>
            <td width="70%">
                <?php
                echo h($value['f_serial'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                氏名
            </th>
            <td>
                <?php
                echo h($value['f_name'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                年齢
            </th>
            <td align="right">
                <?php
                echo h($value['f_age'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                FileMakerの<br>Webはいつから
            </th>
            <td>
                <?php
                echo h($value['f_history'][0]);
                ?>
            </td>
        </tr>
        <tr>
            <th>
                使用したことがある<br>バージョン
            </th>
            <td>
                <?php
                echo h(str_replace("\n", ', ', $value['f_useVersion'][0]));
                ?>
            </td>
        </tr>
        <tr>
            <th>開発に使用<br>しているOS</th>
            <td>
            <?php
            echo h(str_replace("\n", ', ', $value['f_useOS'][0]));
            ?>
            </td>
        </tr>
    </table>
    <?php
    }
    ?>

    <p>
        <?php 
        if (!empty($dataSet['linkPrevious']))
        {
            ?>
            <a href="<?php echo h($dataSet['linkPrevious']); ?>">前のレコードへ</a>
            <?php
        }
        else
        {
            ?>
            前のレコードへ
            <?php
        }
        ?>
        / 
        <?php 
        if (!empty($dataSet['linkNext']))
        {
            ?>
            <a href="<?php echo h($dataSet['linkNext']); ?>">次のレコードへ</a>
            <?php
        }
        else
        {
            ?>
            次のレコードへ
            <?php
        }
        ?>
    </p>

    <ul>
        <li><a href="./fm_edit.php?recid=<?php echo h($recid); ?>">このレコードを編集する</a></li>
        <li><a href="./fm_delete.php?recid=<?php echo h($recid); ?>">このレコードを削除する</a></li>
        <li><a href="./fm_list.php">一覧画面へ移動する</a></li>
    </ul>

</body>

</html>

検索条件もソート条件も一覧画面とまったくおなじ内容で検索をおこなっている。検索条件が簡単な場合はとくに難なく実装できるが、ユーザサイドでの検索条件入力がある場合や複雑な条件の検索をおこなう場合は(1)の実装方法のほうがいいだろう。

一覧とまったくおなじ条件でskipを調節して取得した場合の詳細画面。前後のレコード情報はskipを+1, -1すれば取得可能。検索条件が複雑になればなるほど、動作パフォーマンスやメンテナンスに影響がでやすい

ページャのあるなしを除いては、詳細画面の(1)と(2)で表示している内容はおなじだ。なお、ページ下部にはそれぞれ編集画面、削除、一覧画面へのリンクをつけている。

編集画面の実装

編集画面は新規登録画面の実装とほとんど変わらない。実装にあたり、気をつけるべき箇所はつぎの2点。

  • すでにFileMaker上に登録されているデータを初期値としてあつかうこと
  • 修正ID(-modid)を使用し、排他制御をおこなうこと

編集画面: ファイル - fm_edit.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

// レコードIDの取得用関数
function getRecid($str)
{
    $tmp = explode('.',$str);
    return $tmp[0];
}

// 修正IDの取得用関数
function getModid($str)
{
    $tmp = explode('.',$str);
    return $tmp[1];
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail');
$data->SetDBUserPass($webUN,$webPW);
$viewSet = $data->FMView();

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail', 1);
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$data->SetRecordID($_GET['recid']);

$dataSet = $data->FMFind();
?>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ編集</title>
</head>

<body>

<h1>データ編集</h1>

    <p>
        レコードID: <?php echo h($_GET['recid']); ?> を編集。
    </p>

    <form name="fxphp_crud_c" action="./fm_edit_save.php" method="post">

    <?php
    $n = 0;
    foreach ( $dataSet['data'] as $key => $value )
    {
        $recid = getRecId($key);
        $modid = getModId($key);
    ?>
    <input type="hidden" name="recid" value="<?php echo h($recid);?>">
    <input type="hidden" name="modid" value="<?php echo h($modid);?>">
    <table border="1" width="500">
        <tr>
            <th style="width:30%;">氏名</th>
            <td style="width:70%;">
                <input type="text" name="f_name" id="f_name" value="<?php echo h($value['f_name'][0]); ?>" style="width:70%;">
            </td>
        </tr>
        <tr>
            <th>年齢</th>
            <td>
                <input type="text" name="f_age" id="f_age" value="<?php echo h($value['f_age'][0]); ?>" style="width:20%; text-align:right;">
            </td>
        </tr>
        <tr>
            <th>FileMakerの<br>Webはいつから</th>
            <td>
                <select name="f_history" id="f_history">
                    <option value="">&nbsp;</option>
                    <?php 
                    foreach ($viewSet['valueLists']['valueLists_f_history'] as $valueListsKey => $valueListsValue)
                    {
                        $selected = '';
                        if ( $value['f_history'][0] === $valueListsValue )
                        {
                            $selected = 'selected';
                        }
                        ?>
                        <option value="<?php echo h($valueListsValue); ?>" <?php echo h($selected); ?>><?php echo h($valueListsValue); ?></option>
                        <?php
                    }
                    unset($valueListsKey, $valueListsValue, $selected);
                    ?>
                </select>
            </td>
        </tr>
        <tr>
            <th>使用したことがある<br>バージョン</th>
            <td>
                <?php
                $i = 1;
                foreach ($viewSet['valueLists']['valueLists_f_useVersion'] as $valueListsKey => $valueListsValue)
                {
                    $checked = '';
                    if ( ereg( $valueListsValue . "\n" , $value['f_useVersion'][0] . "\n") )
                    {
                        $checked = 'checked';
                    }
                    ?>
                    <input type="checkbox" name="f_useVersion[]" id="f_useVersion_<?php echo $i ?>" value="<?php echo h($valueListsValue); ?>" <?php echo h($checked); ?>>
                    <label for="f_useVersion_<?php echo $i ?>">: <?php echo h($valueListsValue); ?></label>
                    <?php
                    $i++;
                }
                unset($valueListsKey, $valueListsValue, $i, $checked);
                ?>
            </td>
        </tr>
        <tr>
            <th>開発に使用<br>しているOS</th>
            <td>
                <?php
                $i = 1;
                foreach ($viewSet['valueLists']['valueLists_f_useOS'] as $valueListsKey => $valueListsValue)
                {
                    $checked = '';
                    if ( ereg( $valueListsValue . "\n" , $value['f_useOS'][0] . "\n") )
                    {
                        $checked = 'checked';
                    }
                    ?>
                    <input type="radio" name="f_useOS" id="f_useOS_<?php echo $i ?>" value="<?php echo h($valueListsValue); ?>" <?php echo h($checked); ?>>
                    <label for="f_useOS_<?php echo $i ?>">: <?php echo h($valueListsValue); ?></label>
                    <?php
                    $i++;
                }
                unset($valueListsKey, $valueListsValue, $i, $checked);
                ?>
            </td>
        </tr>
    </table>

    <?php 
    }
    ?>

    <p>
        <input type="submit" value="保存">
    </p>

</form>

</body>

</html>

画面描画前に2回FileMakerにアクセスし、値一覧の情報と登録されているレコード内容を取得している。登録されている内容を<input type="text">ならばvalue=""に、<select><option>ならばselectedとして、<input type="checkbox">・<input type="radio">ならばcheckedとして展開する。また画面には表示させていないが、レコードIDと編集画面描画直前の修正IDも持たせている。

FileMakerに登録されている内容が初期値として展開されている

編集処理: ファイル - fm_edit_save.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail');
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$data->AddDBParam('f_name', $_POST['f_name']);
$data->AddDBParam('f_age', $_POST['f_age']);
$data->AddDBParam('f_history', $_POST['f_history']);
$data->AddDBParam('f_useVersion', implode("\r\n", $_POST['f_useVersion']));
$data->AddDBParam('f_useOS', $_POST['f_useOS']);

$data->SetRecordID($_POST['recid']);
$data->SetModID($_POST['modid']);

$dataSet = $data->FMEdit();

if ( 0 === (int)$dataSet['errorCode'] )
{
    include_once('./fm_edit_reply.php');
}
else
{
    include_once('./fm_edit_error.php');
}

前回紹介したfm_new.phpにSetRecordID, SetModIDでレコードIDと修正IDをセットするように追記している。

編集成功: ファイル - fm_edit_reply.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ編集完了</title>
</head>

<body>

<h1>データ編集 - 完了</h1>

<p>データを編集しました。</p>

<ul>
    <li><a href="./fm_detail_recid.php?recid=<?php echo h($_POST['recid']); ?>">詳細画面へ移動する</a></li>
    <li><a href="./fm_list.php">一覧画面へ移動する</a></li>
</ul>


</body>

</html>

編集に成功した場合に表示する戻り先についてだが、上記コードでは「レコードIDを指定して表示する方法」を採用している。詳細や一覧といった戻り先は、直前に表示したURIを$_SESSIONなどに格納してそれをもちいるといった方法もある。

編集に成功した場合に表示する画面

編集した内容がFileMakerに保存されている

編集失敗: ファイル - fmediterror.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ編集エラー</title>
</head>

<body>

<h1>データ編集 - エラー</h1>

<p>データの編集にエラーが発生しました。<br>FileMaker Error: <?php echo h($dataSet['errorCode']); ?></p>

<ul>
    <li><a href="./fm_edit.php?recid=<?php echo h($_POST['recid']); ?>">編集画面に戻る</a></li>
</ul>


</body>

</html>

修正ID不一致のため、編集に失敗した様子

レコードの編集時に必須なのはレコードIDのみなので、修正IDは指定しなくても動作する。しかしFileMakerにはロールバックといった機能がないため、あるユーザが大事な変更処理をした直後に他のユーザが上書更新してしまった場合、取り返しのつかない状態になる。こういったトラブルを未然に防ぐためにも、修正IDの指定をはじめとした排他制御はかならず組みこむように心がけよう。

削除処理の実装

レコードの削除処理に使用する値は、レコードIDのみだ。修正IDを指定しても無視されてしまうので注意されたい。

削除処理: ファイル - fm_delete.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

// 文字列エスケープ用関数
function h($string)
{
    return htmlspecialchars(trim($string), ENT_QUOTES, 'UTF-8');
}

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'web_detail');
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');

$data->SetRecordID($_GET['recid']);

$dataSet = $data->FMDelete(true);

if ( 0 === (int)$dataSet['errorCode'] )
{
    include_once('./fm_delete_reply.php');
}
else
{
    include_once('./fm_delete_error.php');
}

削除成功: ファイル - fm_delete_reply.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ削除完了</title>
</head>

<body>

<h1>データ削除 - 完了</h1>

<p>データを削除しました。</p>

<ul>
    <li><a href="./fm_list.php">一覧画面へ移動する</a></li>
</ul>


</body>

</html>

削除失敗: ファイル - fm_delete_error.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FX.php データ削除エラー</title>
</head>

<body>

<h1>データ削除 - エラー</h1>

<p>データの削除時にエラーが発生しました。<br>FileMaker Error: <?php echo h($dataSet['errorCode']); ?></p>

<ul>
    <li><a href="./fm_delete_recid.php?recid=<?php echo h($_GET['recid']); ?>">詳細画面に戻る</a></li>
</ul>


</body>

</html>

削除に成功した場合に表示する画面

FileMakerからも完全に削除されていることが確認できる

修正IDを使用した排他制御をしつつ削除処理をおこないたい場合は、完全ではないが次の手順で対応可能だ。

  1. 削除画面へのリンクに修正IDをふくめる
  2. 削除直前にレコードIDで検索をかけ、引数としてわたされた修正IDとFileMaker上の修正IDが一致した場合にはじめて削除処理を実行

FileMakerならではの機能を活用するWebアプリを実装するには?

ここまでざっとFileMakerをバックエンドデータベースにしたWebアプリケーションの実装方法を紹介してきた。簡単なWebアプリならここまで紹介して内容をマスターすればあっという間に実装できるようになるだろう。今回で基礎編はまず終了といったところだ。

さて、FileMakerをバックエンドデータベースとして採用する前にいったん考慮しなければならないことがある。それは「ほかのデータベースと比較したときに、どのようなメリットがあるのか」ということだ。FileMakerはもともとカード型データベースからはじまっているデータベースアプリケーション。その歴史からなるユーザライクなインタフェースが強みだが、コアとなるデータベース自体の機能はMySQLやPostgreSQLと比較するとどうしても見劣りしてしまう。

ややトリッキーな実装をしないとロールバックが実現できないことや、数千~数万クラスのレコードのソートを実行するとき、一度に複数のレコードを操作するときにほかのデータベースと比較してしまうと、その差は顕著に出てしまう。ましてやFileMakerの強みである「ユーザライクなインタフェース」を外に出せないWebアプリケーションの場合は、どこにメリットがあるのかと考えがちだ。

筆者の勝手な考えだが、FileMakerをWebアプリケーションのバックエンドデータベースエンジンとして採用するメリットは「公開/スタックするデータをエンドユーザがFileMakerをつかって自由に加工ができること」「業務フローが途中で変わっても、データベース側で対応がしやすい」の2点だと考えている。単体のデータベースエンジンとしてみた場合は心もとないが、データ加工に関しては初心者ユーザから上級者ユーザまで持ち前のUIでかなり自由度のたかい加工ができるようになっている。最初から用意されている数多い集計帳票のテンプレートが最たる例だ。またGUI・ユーザ側で作成できるスクリプトステップの内容も充実しており、直感的にテーブル構造や処理の変更ができるようになっている。

Webアプリ上でFileMakerのデータを操作(登録/変更/削除)し、スタックされたデータをFileMakerユーザが自由に加工して帳票や外部システム連携用のCSVなどを作成、2次利用・3次利用していく……。まだ業務フローが確立しきっていないがきっちりシステムを組む前にまずはWebアプリ化で業務がどう変わるのかを試してみたい場合や、既存のFileMakerで構成されたシステムがある環境、社内にFileMakerをバリバリ使えるユーザが在籍しているときに「FileMakerをデータベースに採用したWebアプリケーション」は選択肢のひとつとして光るのではないだろうか。

次回以降では、いよいよFileMakerと密接に連携したWebアプリケーションの実装方法を紹介していこう。