「 FileMaker Data API を実行 」を使って親子関係のレコードを複製する

Claris FileMaker 2024 で、スクリプトステップ「FileMaker Data API を実行」に CUD(Create、Update、Delete)がサポートされました。

この新機能により、FileMaker 開発者はウィンドウやレイアウトを変更することなく、親子関係のレコードを登録・編集できるようになります。さらに、エラー発生時には処理をなかったことにできるトランザクションのような機能も備わっています。

参考記事: Claris FileMaker 2024 – 「 FileMaker Data API を実行」スクリプトの CUD サポート

カスタム App において、あるレコードを操作中にそれと関連するテーブルにレコードを登録・更新することはよく利用される手法です。このスクリプトステップの登場により、これまでのやり方とは異なる方法での実装が可能となり、今後この技術が様々に活用されることが期待されます。

これまでの手法との違い

今回の記事で紹介するのは、親子関係を含めたレコードの複製です。追加された機能に「複製(action:duplicate)」がありますが、これは指定した親レコードのみの複製で、ポータルなど子に相当する関連レコードは複製されません。この点は通常の FileMaker の複製機能と同じです。

通常の FileMaker においてポータルなどの親子関係を含めたレコードの複製を行う際には、スクリプトで変数にポータル内のデータをセットして親レコードを複製後に展開させたり、ポータルデータをエクスポートして親レコード作成後にインポートし直すなど、開発者が様々なテクニックで実装してきました。

新しい「FileMaker Data API を実行」では、ポータルを含んだ親子関係のレコード登録をサポートしているため、action は duplicate ではなく create を使い、現在のレコード情報を JSON 形式のデータにセットすれば複製と同じ動きが実現できます。万が一、ポータル内のデータの一部が登録できないような事態(エラー発生)の場合、今回複製しようとしたレコードの書き込みはキャンセルされるため、エラーが発生してもゴミデータが残ることはありません。

いかに現在のレコード情報を「 FileMaker Data API を実行」の引数へセットするのかというところがポイントになります。また工夫次第でとても簡単に親子関係のレコード複製ができます。これは後述します。

親子関係のレコード複製時の JSON の構成

「FileMaker Data API を実行」で親子関係のレコード複製を行うためには、現在のレコード情報をセットした JSON データを作成する必要があります。以下の手順で実行します。

まず、登録に必要な action や layouts オプションを指定し、親テーブルで複製させたいフィールド情報をセットします。

変数を設定 [ $json ;
  JSONSetElement ( "{}";
    [ "action" ; "create" ; JSONString ] ;
    [ "layouts" ; "売上入力" ; JSONString ] ;
    [ "dateformats" ; 1 ; JSONNumber ] ;
    [ "fieldData.売上日" ; 売上管理::売上日 ; JSONString ] ;
    [ "fieldData.得意先名" ; 売上管理::得意先名 ; JSONString ] ;
    [ "fieldData.件名" ; 売上管理::件名 ; JSONString ] 
  )

複製時に値を上書きしたいフィールドがある場合は、ここで設定します。

※「dataformats」オプションについては、弊社ブログの過去記事に詳しく紹介しています。

https://kotovuki.co.jp/archives/13757)

なお、上記記事の段階では dateformats が適用されるのは read のみで書き込みには対応していませんでしたが、今回のバージョンから書き込み時にも対応するようになりました。

上記で作成した $json へ次の処理でさらに関連レコードの値をセットしていきます。

変数を設定 [ $no ; 値 : 0 ]
Loop [ フラッシュ ]
  ポータル内の行へ移動 [ $no +1 ]
  Exit Loop If [ IsEmpty ( 売上明細::No ) ]
    変数を設定 [ $json ; 
      JSONSetElement ( $json ; 
        [ "portalData.売上明細[" & $no & "].売上明細::内容" ; 売上明細::内容 ; JSONString ] ;
        [ "portalData.売上明細[" & $no & "].売上明細::単価" ; A02_見積明細::単価 ; JSONString ] ;
        [ "portalData.売上明細[" & $no & "].売上明細::数量" ; A02_見積明細::数量 ; JSONString ] 
      )
  変数を設定 [ $no ; 値 : $no + 1 ]
End Loop

登録用の JSON ができたら「FileMaker Data API を実行」します。

FileMaker Data API を実行 [ ターゲット: $$result ; $json ]

これでポータルデータを含めた新しいレコードが作成されます。ただし、このままでは元のレコードの画面のままなので、複製したレコードに移動したいときは、実行後に返ってきた JSON から作成されたレコード ID がわかるので、そこから新しく作られたレコードに移動するようにします。

action の read を活用したレコード複製時の JSON の構成

また、工夫次第で「FileMaker Data API を実行」で行う親子関係の複製が簡単にできる点も紹介します。

以前から実装されている action の read を使い、現在の recordId でリクエストすると、レイアウト上に配置されているレコード(ポータルのデータを含む)の各フィールド値を JSON 形式で取得できます。現在のレコードの情報は以下のように取得できます。

FileMaker Data API を実行 [ ターゲット : $$result ;
  JSONSetElement ( "{}" ;
    [ "action" ; "read" ; JSONString ] ;
    [ "layouts" ; Get ( レイアウト名 ) ; JSONString ] ;
    [ "recordId" ; Get ( レコード ID ) ; JSONNumber ]
  )
]

取得できた JSON(レコード情報)は以下のようになります。

{
  "messages" : 
  [
    {
      "code" : "0",
      "message" : "OK"
    }
  ],
  "response" : 
  {
    "data" : 
    [
      {
        "fieldData" : 
        {
          "件名" : "新 Data API を実行のテスト",
          "得意先名" : "株式会社 API",
          "売上日" : "2024/05/28"
        },
        "modId" : "0",
        "portalData" : 
	{
	  "売上明細" : 
	  [
	    {
	      "売上明細::内容" : "1行目だよ",
	      "売上明細::単価" : 10000,
	      "売上明細::数量" : 1,
	      "modId" : "0",
	      "recordId" : "36"
	    },
	    {
	      "売上明細::内容" : "2行目だよ",
	      "売上明細::単価" : 12000,
	      "売上明細::数量" : 1,
	      "modId" : "0",
	      "recordId" : "37"
	    }
	  ]
        },
	"portalDataInfo" : 
	[
	  {
	    "database" : "売上管理",
	    "foundCount" : 2,
	    "returnedCount" : 2,
	    "table" : "売上明細"
	  }
	],
	"recordId" : "26"
      }
    ],
    "dataInfo" : 
    {
      "database" : "売上管理",
      "foundCount" : 1,
      "layout" : "売上入力",
      "returnedCount" : 1,
      "table" : "売上管理",
      "totalRecordCount" : 8
    }
  }
}

message オブジェクト内にエラー情報などがあり、response オブジェクト内に data オブジェクトがあり、その中に各フィールド内の情報があります。

見ると、response.data 以下の JSON の構文は create や update に必要な情報とほとんど同じであることがわかります。つまり、recordId を指定して read で現在のレコード情報を取得し、その JSON の不要なオプションを消去し、必要なオプションを追加すれば、そのまま複製するための create 用の JSON になります。

不要なオプションとは、親レコードの recordID、modId、そして各ポータル行の recordId、modId や portalDataInfo オプションです。必要なオプションは action、layouts です。

JSONDeleteElement や JSONSetElement を使って上記の要素を消去、追加すれば、各フィールドに値をセットするような記述をしなくても済みます。とても簡単です。以下のように実行します。

注意点としては、read で取得する際のポータルレコードの取得件数が初期値(指定しない場合)で 50 になっています。ポータルのレコード件数が多い場合はオプションの「limit.ポータル名」を使い、全ての件数を取得できるように指定します。

まずは現在のレコード情報を取得します。

FileMaker Data API を実行 [ ターゲット : $result ;
  JSONSetElement ( "{}" ;
    [ "action" ; "read" ; JSONString ] ;
    [ "layouts" ; Get ( レイアウト名 ) ; JSONString ] ;
    [ "recordId" ; Get ( レコード ID ) ; JSONNumber ] ; 
    [ "['limit.売上明細']" ; 100 ; JSONNumber ]
  )
]

返ってきた JSON からフィールド情報部分のみを取得します。

変数を設定 [ $json ; JSONGetElement ( $result ; "response.data[0]" ) ]

複製するために必要なオプション(action, layouts)を追加します。

変数を設定 [ $json ; 
  JSONSetElement ( $json ;
    [ "action" ; "create" ; JSONString ] ;
    [ "layouts" ; Get ( レイアウト名 ) ; JSONString ] 
  )

不要なオプションを消去していきます。recordId と modId そして portalDataInfo を消去します。まずは親テーブルから。

変数を設定 [ $json ; JSONDeleteElement ( $json ; "recordId" ) ]
変数を設定 [ $json ; JSONDeleteElement ( $json ; "modId" ) ]
変数を設定 [ $json ; JSONDeleteElement ( $json ; "portalDataInfo" ) ]

次にポータル関連の不要なオプションを消去します。ポータル名は直接指定するか、JSON 情報の中から JSONListKeys で取得するなどしてポータル内の不要オプションを消去します。

変数を設定 [ $portalName ; 値 : JSONListKeys [ $json ; "portalData" ] ]
変数を設定 [ $c ; 値 : 1 ]
Loop [ フラッシュ ] 
  変数を設定 [ $portal ; GetValue ( $portalName ; $c ) ]
  If [ Not IsEmpty ( $portal ) ] 
    変数を設定 [ $no ; 値 : 0 ]
    Loop [ フラッシュ ]
      Exit Loop If [ not JSONGetElement ( $json ; "portalData." & $portal & "[" & $n & "].recordId" ) ]
      変数を設定 [ $json ; 値 : JSONDeleteElement ( $json ; "portalData." & $portal & "[" & $n & "].recordId" ) ]
      変数を設定 [ $json ; 値 : JSONDeleteElement ( $json ; "portalData." & $portal & "[" & $n & "].modId" ) ]
      変数を設定 [ $no ; 値 : $no + 1 ]
    End Loop
  End If
  Exit Loop If [ IsEmpty ( $portal ) ]
  変数を設定 [ $c ; 値 : $c + 1 ]
End Loop

これで取得した JSON に必要なオプション(action、layouts)を追加し、不要なオプション(recordId、modId)を消去した複製用の JSON が完成しました。

複製用の JSON ができたら、あとは実行するだけです。

FileMaker Data API を実行 [ ターゲット: $$result ; $json ]

これで親子関係の複製ができます。非常に簡単です。便利な点として、上記で紹介したスクリプトは、どのレイアウトでも使える汎用的なスクリプトにすることができます。

このやり方の場合、「工夫次第で」とつけたのは、この JSON の fieldData や portalData の中に記述されているフィールドにデータを入れられないフィールドが含まれている時は、そのままでは実行できないためです。

データを入れられないフィールドとは、計算フィールドや集計フィールド、オブジェクトフィールドです。これらのフィールドを含んだ状態で実行すると、エラーが発生し完了できません。

これを避けるには、取得した JSON データからさらにこれらインポート不可のフィールド名など不要な要素を JSONDeleteElement を使って消去するか、あらかじめ複製時に必要なフィールドのみ配置したレイアウトを別途作成しておき、そのレイアウトを使って複製処理を行うことが可能です。

スクリプト実行時に引数で複製させないフィールドや初期値を設定したいフィールド、複製したいポータル名などを渡して、上記のスクリプト中で引数で渡されたフィールドを除外したり初期値を設定するような処理を加えたり、action の metaData を活用して配置されているフィールドのタイプ情報などを取得して処理を加えることで、より汎用的な処理が可能になります。

まとめ

  • 現在のレコード情報を JSON 形式のデータにセットし、action の create を使えば複製と同じ動きができます。
  • action の read を使えば作成に必要な JSON がほとんどできているので、そこから不要なオプションを消去し、必要なオプションを追加すれば、より簡単に複製が可能です。

この「FileMaker Data API を実行」は、レコード登録・更新の新たなインターフェースとなる技術です。様々な活用方法で今後利用されていくことになると思います。ご参考ください。