FileMaker Webアプリを実装するにあたり、FX.php, FileMaker API for PHPの使い方やパフォーマンス比較を紹介してきた。FMCakeMixの動向を追う第3回目は「OR検索のサポート」「FileMakerスクリプト実行のサポート」を中心に、FMCakeMixでOR検索を実行する場合・FileMakerスクリプトを実行する方法を取りあげる。

FMCakeMixでOR検索をおこなうには

5月11日(米国時間)に、OR検索がおこなえるように修正がおこなわれた。これはもともとFileMaker Web公開がサポートしている-lop引数を利用したもの。コントローラ(/app/controller/*.php)で検索をおこなう際に$conditionsに「or」という文字列を渡すと、dbo_fmcakemix.php側でFX.phpのSetLogicalOR()がコールされるという仕組みだ。DBOドライバの実装部分は次のとおり。

dbo_fmcakemix.php 213-251行目より

    if(!empty($queryData['conditions'])) {
      $conditions = array(); // a clean set of queries
      $isOr = false;  // a boolean indicating wether this query is logical or

      foreach($queryData['conditions'] as $conditionField => $conditionValue) {
        // if a logical or statement has been pased somewhere
        if($conditionField == 'or') {
          $isOr = true;
          if(is_array($conditionValue)) {
            $conditions = array_merge($conditions, $conditionValue);
          }
        } else {
          $conditions[$conditionField] = $conditionValue;
        }
      }

      // look for condition operators set in conditions array
      // remove them then include them fx style in the query
      $operators = array();
      foreach($conditions as $conditionField => $conditionValue) {
        $operator = $this->parseConditionField($model, $conditionField, 'operator');
        $field = $this->parseConditionField($model, $conditionField, 'field');
        if ($operator) {
          $operators[$field] = $conditionValue;
          unset($conditions[$conditionField]);
        }
      }

      foreach($conditions as $conditionField => $conditionValue) {
        $field = $this->parseConditionField($model, $conditionField, 'field');

        $this->connection->AddDBParam($field, $conditionValue, isset($operators[$field]) ? $operators[$field] : 'eq');

        //add or operator
        if($isOr){
          $this->connection->SetLogicalOR();
        }
      }
    }

FX.php 1822-1825行目より

    function SetLogicalOR ()
    {
        $this->AddDBParam('-lop', 'or');
    }

$conditionField中に「or」が存在していれば、$isOrがtrueとなる。$isOrがtrueの場合は、引用部分の最下部で「$this->connection->SetLogicalOR();」がコールされる。実際に使用する場合のコードサンプルと、サンプルに使用するFileMakerデータベース情報は次のとおり。

  • FileMakerファイル名: fmcake_test
  • FileMakerレイアウト名: fmcake_setlogicalor_test
  • 配置したフィールド: name(テキスト), license(テキスト)
  • データベースへ接続するための/conf/database.phpは前回を参照

レイアウト「fmcake_setlogicalor_test」に配置したフィールドと、セットした内容

モデル記述例

class logicalOrList extends AppModel
{
    var $fmDatabaseName = 'fmcake_test';
    var $defaultLayout = 'fmcake_setlogicalor_test';
}

コントローラ記述例

function logicalOrList()
{
    $this->layout = false;
    $this->loadModel('logicalOrList');

    $condition = array
    (
       'or' => true,
       'license' => 'The BSD License',
       'lang' => 'JavaScript'
    );
    $this->set('result', $this->paginate('logicalOrList', $condition));
}

ビュー記述例

<table border="1">
    <thead>
        <tr>
            <th><?php echo $paginator->sort('ライブラリ名', 'name'); ?></th>
            <th><?php echo $paginator->sort('ライセンス', 'licence'); ?></th>
            <th><?php echo $paginator->sort('言語', 'lang'); ?></th>
        </tr>
    </thead>

    <tbody>
    <?php
    foreach ($result as $value)
    {
    ?>
        <tr>
            <td><?php echo $value['logicalOrList']['name']; ?></td>
            <td><?php echo $value['logicalOrList']['license']; ?></td>
            <td><?php echo $value['logicalOrList']['lang']; ?></td>
        </tr>
    <?php
    }
    ?>
    </tbody>
</table>

この場合の検索条件は、「"licenseがThe BSD License"または"langがJavaScript"であること」となる。/fmi/xml/FMPXMLRESULT.xmlに発行されるクエリは「-db=fmcake_test&-lay=fmcake_setlogicalor_test&-max=20&-sortfield.1=name&-sortorder.1=ascend&license.op=eq&license=The+BSD+License&-lop=or&lang.op=eq&lang=JavaScript&-lop=or&-find」。これをWebブラウザで表示する。

「"licenseがThe BSD License"または"langがJavaScript"であること」の検索条件にマッチしたレコード一覧が表示された

$conditionsからorを外せばAND検索となる

FX.phpのSetLogicalOR()をそのまま使用するということでピンとくる方もおおいと思う。お察しのとおり、FMCakeMixでANDとORの複合検索を実装する場合は非常に骨が折れる。FX.phpまたはFileMaker API for PHPを使ってこれら複合検索の実装を確立している場合は、該当のコントローラ部分でのみ、その仕組みを流用するようにしてやると手っ取り早い。

FMCakeMixでFileMakerスクリプトを実行する方法

5月11日(米国時間)に、FMCakeMixからFileMakerスクリプトを実行できるように修正がおこなわれた。FileMaker Web公開マニュアル(FileMaker Server Custom Web Publishing with XML and XSLT 101-103ページ)に記載されている6種類すべての引数に対応している。

  • -script: 検索・ソート実行後にスクリプトを実行
  • -script.prefind: 検索実行前にスクリプトを実行
  • -script.presort: ソート実行前にスクリプトを実行
  • -script.param: -scriptで指定したスクリプトに引数を付与
  • -script.prefind.param: -script.prefindで指定したスクリプトに引数を付与
  • -script.presort.param: -script.presortで指定したスクリプトに引数を付与

処理の順番は早い順に –script.prefind > –script.presort > –script となる。これらの引数はdbo_fmcakemix.php内部で特別なパラメータとして扱われており、スキーマに格納される。

dbo_fmcakemix.php 50-59行目より

  // warning: these get added to schema, but allow you to pass in values
  // so that the xml api parses them as functional parameters
  var $allowed_parameters = array(
    '-script',
    '-script.prefind',
    '-script.presort',
    '-script.param',
    '-script.prefind.param',
    '-script.presort.param'
  );

dbo_fmcakemix.php 650-659行目より

    // add in fm xml functional parameters so that they don't get cleaned from saves
    foreach ($this->allowed_parameters as $param) {
      $fieldsOut[$param] = array(
        'type' => 'FM_PARAM',     
        'null' => null, 
        'default' => null, 
        'length' => null, 
        'key' => null
      );
    }

使用する場合はOR検索と同様、$conditionsに上記6種類のパラメータと、FileMakerスクリプト名または引数を指定してやればOKだ。試しに特定のフィールドを全置換するFileMakerスクリプトをFMCakeMixから実行させてみよう。

  • FileMakerファイル名: fmcake_test
  • FileMakerレイアウト名: fmcake_script_test
  • 配置したフィールド: num(数字)
  • 実行するFileMakerスクリプト: replaceAll_num (スクリプトステップは別画像を参照)

FileMakerスクリプト「replaceAll_num」。numフィールドをランダムな数字で全置換する

あらかじめ10レコード用意した

モデル記述例

class execFmScript extends AppModel
{
    var $fmDatabaseName = 'fmcake_test';
    var $defaultLayout = 'fmcake_script_test';
}

コントローラ記述例

function execFmScript()
{
    $this->layout = false;
    $this->loadModel('execFmScript');

    $this->paginate['limit'] = 10;

    $condition = array
    (
       '-script' => 'replaceAll_num',
    );
    $this->set('result', $this->paginate('execFmScript', $condition));
}

ビュー記述例

<table border="1">
    <thead>
        <tr>
            <th><?php echo $paginator->sort('num'); ?></th>
        </tr>
    </thead>

    <tbody>
    <?php
    foreach ($result as $value)
    {
    ?>
        <tr>
            <td><?php echo $value['execFmScript']['num']; ?></td>
        </tr>
    <?php
    }
    ?>
    </tbody>
</table>

FX.phpのPerformFMScript()やFileMaker API for PHPのsetScript()と違い、専用のメソッドを使用することはない。これをWebブラウザで表示する。

FileMakerスクリプトが実行され、numフィールドがすべてRandomで全置換されている

OR検索の実行、FileMakerスクリプトの実行ともにFX.phpやFileMaker API for PHPと使い勝手が違う。実行するまでの手順が違うだけなので、しっかり覚えておけばそこまで苦労することもなさそうだ。FMCakeMixでFileMaker特有の処理をしたいが書き方がわからないという方は、前回の記事と合わせてしっかりDBOドライバの実装を追ってほしい。