FMCakeMixでFileMakerスクリプトをWebから実行しようとした場合、CakePHPの仕組み上、スクリプトが二重起動してしまう。レコードの検索を補助するようなスクリプトなら二重起動しても問題ないが、レコードの作成・編集・削除をともなうスクリプトの場合、二重起動すると本来意図した動作とは違う結果をまねいてしまう。スクリプトの処理自体が長い場合、おなじ処理が2回おこなわれることでパフォーマンスの低下も発生する。FMCakeMixでこれらスクリプトの二重起動を防ぐ方法を2通り紹介しよう。

FMCakeMixでFileMakerスクリプトの二重起動を防ぐ方法

FMCakeMix(CakePHP)のPaginateを使った実装の場合、最初にデータ数をカウントするクエリを発行する。一度の処理でFileMaker Web公開エンジンに2回のリクエストが飛ぶというわけだ。このとき-scriptや-script.paramといった値もクエリ内に含まれてしまい、FileMakerスクリプトの二重起動をまねく。スクリプトの処理自体が長い場合、おなじ処理が2回おこなわれることでパフォーマンスの低下も発生する。できることなら避けたい現象だ。

このスクリプトの二重起動を防ぐにあたり、おもに2通りの実装方法がある。

  1. Paginateを使わず、find()やFX.phpのメソッドを使う
  2. dbo_fmcakemix.php本体を修正し、データ数をカウントするクエリの中に-scriptに関連するパラメータがふくまれないようにする

1. Paginateを使わず、find()やFX.phpのメソッドを使う

FileMakerスクリプトを使用したいアクション内ではPaginateを使わず、find()やFX.phpのメソッドを使って実装をおこなう方法。find()ではconditionsとしてわたす条件の中に、-scriptや-script.paramを含めることでスクリプトを起動させる。

function index()
{   
    $this->set
    (   
        'result', 
        $this->(モデル名)->find
        (   
           'all',
            array
            (   
                'conditions' => array
                (   
                    '-script' => '(スクリプト名)', 
                    '-script.param' => '(スクリプト引数)'
                ),  
            )   
        )
    );      
}

この修正だけだと-script.opや-script.param.opといったクエリが作られてしまうので、dbo_fmcakemix.phpの244行目前後を修正する。

// $this->connection->AddDBParam($field, $conditionValue, isset($operators[$field]) ? $operators[$field] : 'eq');
if(in_array($field, $this->allowed_parameters))
{
    $this->connection->AddDBParam($field, $conditionValue);
}
else 
{
    $this->connection->AddDBParam($field, $conditionValue, isset($operators[$field]) ? $operators[$field] : 'eq');
}

allowed_parametersはdbo_fmcakemix.phpのファイル先頭部分で宣言されている、スクリプト起動に関わるパラメータが格納された配列。これで$conditionsに-script*といった引数を渡しても、op検索演算子がつくことはなくなる。

findを使ったスクリプトの起動。スクリプトが二重で起動することはない

FX.phpのメソッドはFMCakeMix本体で利用しているため、そのままnew FX()でコードを書けばOKだ。

function index()
{
    $data = new FX('localhost', 80, 'FMPro9', 'http');
    $data->SetDBUserPass('(ユーザID)','(パスワード)');
    $data->SetCharacterEncoding('utf8');
    $data->SetDataParamsEncoding('utf8');
    $data->AddDBParam('-script','(スクリプト名)');
    $data->AddDBParam('-script.param','(スクリプト引数)');
    $dataSet=$data->FMFind();

    $this->set(result, $dataSet['data']);
}

検索条件が固定されている場合や、単純にスクリプトを起動させたいだけならこの方法で代用が可能だ。当然ながらこの実装方法の場合「Paginateを使った検索に該当した対象レコードに対してスクリプトを実行する」といったことはできないで注意されたい。

2. dbo_fmcakemix.php本体を修正し、データ数をカウントするクエリの中に-scriptに関連するパラメータがふくまれないようにする

こちらはdbo_fmcakemix.php本体を修正し、Paginateでデータ数をカウントするクエリを生成する前に$codntionsからスクリプト起動に関連するパラメータを除外してしまうという方法だ。$conditionsから削除するパラメータは次の6種類。

  • -script: 起動させるスクリプト名
  • -script.param: -scriptに対応するスクリプト引数
  • -script.prefind: 検索実行前に起動させるスクリプト名
  • -script.prefind.param: -script.prefindに対応するスクリプト引数
  • -script.presort: 検索実行後、ソート前に起動刺せるスクリプト名
  • -script.presort.param: -script.presortに対応するスクリプト引数

FMCakeMixのアクションより渡す$conditionsからこれらを削除する構文を、FMCakeMixの198-205行目に追記する。

// set connection data if Count query
if($queryData['fields'] == 'COUNT') {
  // reset the connection parameters to return only 1 result, improves performance
  $this->connection->SetDBData($fm_database, $fm_layout, 1);
  // delete -script* from conditions if Count query
  unset($queryData['conditions']['-script']);
  unset($queryData['conditions']['-script.param']);
  unset($queryData['conditions']['-script.prefind']);
  unset($queryData['conditions']['-script.prefind.param']);
  unset($queryData['conditions']['-script.presort']);
  unset($queryData['conditions']['-script.presort.param']);
} else {
  // set basic connection data
  $this->connection->SetDBData($fm_database, $fm_layout, $queryLimit);
}

"delete -script* from conditions if Count query"以降のunset部分が追記をおこなったコード。この修正をおこなうことで、最初にデータ数をカウントするリクエストが発行されても、その時はスクリプトが起動しないようになる。2回目の検索リクエスト時には-scriptをはじめとしたパラメータがクエリにふくまれるため、スクリプトが起動する。二重起動はしなくなるというわけだ。

修正前のPaginateを使ったスクリプトの起動。赤線部に注目すると、スクリプトが二重で起動していることがわかる

修正後のPaginateを使ったスクリプトの起動。スクリプトの二重起動は発生していない

この修正の問題点は、スクリプトの起動有無で対象レコード数が上下する場合、データ数をカウントするリクエストで正しいレコード数が取得できなくなってしまうという点。たとえばスクリプト中で別の検索やレイアウトの移動、関連レコードへ移動といったスクリプトステップを使用していた場合、スクリプトを起動するのとしないとでは結果レイアウトやレコード数が違ってくる。修正自体の影響範囲も大きいことから、これらの動作が見込まれるスクリプトをWebアプリケーションから実行する場合には要注意だ。この場合は1のPaginateを使わない実装のほうが良いかもしれない。

凝った動作が要求されるFileMaker Webアプリケーションを実装するにあたり、スクリプトの活用は必要不可欠。FMCakeMixをフレームワークとして採用している場合、スクリプトを活用する際は注意が必要だ。複雑なスクリプトをいくつもの場面で起動させたい場合は、いまのところFX.php単体でWebアプリケーションを組んだ方がトラブルが少ない可能性がある。将来ほかのデータベースでの再構築を考慮するならばFMCakeMix+FX.php、運用開始後もFileMakerとスクリプトで複雑な処理を実装していくならFX.php単体というふうにある程度使い分けができるようになっておこう。