0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プリザンターのサーバスクリプトと拡張SQLの実行タイミングを操作別にみてみる[前編:画面表示・保存・フォーム]

0
Posted at

はじめに

「更新前」のサーバスクリプトと「更新前」の拡張 SQL は、どちらが先に動くのでしょうか。フォームを送信したときは、通常の新規作成と同じ条件になるのでしょうか。

実行条件の一覧だけでは判断しにくいので、まず一覧を開き、レコードを編集して保存するところから本体の処理を追ってみます。前編では、一覧・編集・作成・更新とフォーム送信を扱います。後編のテーマは、入力途中の処理・一括操作・APIです。

プリザンター 1.5.9.0 のソースを対象にしています。実機での動作確認は行っていません。図は主要なフックの相対順を示し、呼び出し回数を固定するものではありません。

サーバースクリプトと拡張サーバースクリプトは、同じ実行条件で動きます。同じ条件では拡張サーバースクリプト → サイトのサーバースクリプトの順です。拡張 SQL は、それとは別に SQL を組み立てたり DB を更新したりする位置で適用されます。

「更新前」という名前だけでは、計算式・入力チェック・DB 更新との前後関係までは分かりません。この記事では画面操作を起点に、どの条件がどこで呼ばれるかを追います。

ソースで追う範囲

公式のサーバスクリプトの条件と拡張サーバスクリプト設定に対して、この記事では複数の機能をまたぐ呼び出し順を補います。

図は記録テーブル(Results)の通常の処理をソースから整理したものです。期限付きテーブル(Issues)も、作成・更新の主要なフックの前後関係は同じです(IssueModel.cs の作成、更新)。Wiki・フォルダは対象に含めません。この前編では、通常の一覧・編集画面とフォームの経路を扱います。

図中の「SS」は、条件に合う拡張サーバースクリプトとサイトのサーバースクリプトの両方を表します。有効なスクリプトと拡張 SQL が登録されている前提です。通知・サマリ・添付ファイルなどの細部は省略しています。図は実機ログではなく、ソースで確認した主要なフックの相対順です。リンク項目などによる追加取得や再計算があるため、呼び出し回数を固定する図ではありません。

「いつ」と「どの操作」を分ける

判定するもの 意味 例
context.Condition 今どのフックで実行されているか BeforeOpeningPage、BeforeUpdate
context.Controller どのコントローラへのリクエストか items、forms
context.Action リクエストの操作名 index、edit、update、create

Controller・Action はルートの値を小文字にしたものです。画面の見た目ではなく、現在のリクエストを表します(Context.cs)。

操作 Controller Action まず着目する SS の条件 保存用の拡張 SQL
一覧画面を開く items index WhenViewProcessing、BeforeOpeningPage、各行の WhenloadingRecord・BeforeOpeningRow 作成・更新系は呼ばれない
既存レコードの編集画面を開く items edit WhenViewProcessing、WhenloadingRecord、BeforeOpeningPage 作成・更新系は呼ばれない
新規作成画面を開く items new BeforeFormula・AfterFormula、BeforeOpeningPage 作成系はまだ呼ばれない
新規レコードを作成する items create BeforeCreate、AfterCreate OnCreating、OnCreated
既存レコードを更新する items update BeforeUpdate、AfterUpdate OnUpdating、OnUpdated
フォームを開く forms new BeforeFormula・AfterFormula、BeforeOpeningPage 作成系はまだ呼ばれない
フォームを送信する forms create BeforeCreate、AfterCreate OnCreating、OnCreated
送信完了画面に移動する forms thanks WhenloadingSiteSettings 再度の作成は行わない

上の表は着目点の早見表です。各経路でサイト設定を読み込む WhenloadingSiteSettings があり、保存時には入力の反映・計算式・レコードの再取得もあります。全条件が1回ずつ動くという意味ではありません。

操作名は ItemsController.cs、新規・編集、作成・更新、FormsController.csで確認できます。

同じ条件での実行順

本体は拡張サーバースクリプトを先に並べ、サイトのスクリプトを後ろに連結します。その一覧から、現在の実行条件に合うものを選びます(SiteSettings.cs、ServerScriptUtilities.cs)。

拡張側の Controllers・Actions は対象リクエストを絞る条件です。Actions に update を指定するだけでは実行タイミングは決まりません。BeforeUpdate なども指定します。Controllers・Actions の肯定指定は大文字・小文字を区別するので、リクエストと同じ小文字で指定します。また、肯定指定と除外指定を同じリストに混ぜると、除外側の判定で対象が広がる場合があります。操作を限定するときは、肯定指定でそろえて実行条件と組み合わせます(条件の評価)。

一覧画面を開いたとき

操作手順は「記録テーブルの一覧を開く」です。通常の一覧表示では items/index になります。

一覧データの取得は、BeforeOpeningPage より先です。一覧の検索条件を変えるなら WhenViewProcessing を使います。 BeforeOpeningPage では取得済みの gridData を扱えますが、そこでビューを変更するだけで、先に行われた一覧取得をやり直すわけではありません。

WhenloadingRecord は一覧全体に対して1回ではなく、行のモデルを作る際にも呼ばれます。その後に BeforeOpeningRow があり、行の見た目を組み立てます。表示行が多いほど、行ごとの処理も増えます。

根拠は ResultUtilities.cs の一覧取得から画面フックまで、GridData.cs の SELECT、行モデルと行フック、レコード読み込みフックです。

選択系の拡張 SQL は何をするか

設定 適用する場所
OnSelectingWhere SELECT の WHERE 条件
OnSelectingOrderBy SELECT の ORDER BY
OnSelectingColumn SELECT の列式

これらは、作成・更新系のように独立した SQL を前後に流すフックとは性格が異なり、本体の SELECT に組み込む SQLです。設定名に「Selecting」があっても、別の SQL が3本順番に実行されるという意味ではありません(View.cs の WHERE、ORDER BY、Rds.cs の列式)。

WhenViewProcessing は一覧専用ではありません。編集対象の取得も View.SetColumnsWhere を通るため、編集時や保存中の再取得でも呼ばれます。一覧だけを対象にするなら、操作名も確認します(ResultModel.Get)。

フィルター・ソートで一覧を読み直す

初回の一覧表示の後に、フィルターやソートを変更して行を取得し直す items/gridrows の経路もあります。ここでは一覧データを取得した後に BeforeOpeningPage を呼び、返す行を描画します。index だけに絞った処理は、この経路に適用されません。一覧の検索条件を継続して適用するなら、gridrows も対象に含めます(ItemsController.GridRows、ResultUtilities.GridRows)。

編集画面を開いたとき

操作手順は「一覧で既存レコードを選び、通常の編集画面を開く」です。items/edit で、作成・更新はまだ行いません。

BeforeOpeningPage には、取得済みの編集対象モデルが渡されます。一覧で各行に使う BeforeOpeningRow は、編集対象1件の通常のエディタ描画には使いません。ただし編集画面内のリンク先一覧などが行を描画する場合は、追加の行フックがあり得ます。

根拠は 編集モデルの生成、取得してから入力を反映するコンストラクタ、画面フックへのモデルの受け渡し、リンク先の行フックです。

編集画面を保存したとき

「保存」は、新規なら作成、既存なら更新に分かれます。まず、既存レコードの値を変更して更新する場合を見ます。

押さえたい順序は BeforeUpdate → OnUpdating → 本体更新 → OnUpdated → AfterUpdate です。

標準の更新時検証は BeforeUpdate より先に行われます。「更新前なら、すべての検証より前」ではありません。入力値を反映する SetByForm は、その中で計算式の処理を呼びます。したがって、BeforeFormula・AfterFormula も BeforeUpdate より前に現れます。プロセス処理などによる追加の計算は図では省略しています(ResultUtilities.Update、入力反映、計算式フック)。

OnUpdating は本体更新の SQL リストの先頭側に追加されます。OnUpdated は、その最初の更新処理が終わった後、関連情報を更新する別の SQL リストに追加されます。前後の拡張 SQL と保存全体を、単一のトランザクションで囲んでいるわけではありません。 後続処理のエラーで、既に終わった DB 更新まで一括で戻ると想定しないでください(更新前と本体更新、関連更新と更新後フック、関連更新内の SQL)。

保存後の画面表示も同じリクエストに含まれる

通常の更新応答は、編集画面を再描画する経路を通ります。このとき BeforeOpeningPage の Action は update のままです。BeforeOpeningPage と Action = edit を組み合わせると、最初に編集画面を開いたときに絞れますが、更新後の再描画は対象から外れます。

General.json の UpdateResponseType の既定値は 0 です。通常の未ロックのレコードで 1 にすると項目差分を返す経路になり、同じ再描画フックを必ず通るとは限りません。ダイアログ編集も一覧行の置換という別経路です(General.json、ResponseByUpdate、EditorResponse)。

新規作成を保存する場合

新規作成画面を開く操作は items/new、作成ボタンを押す操作は items/create です。画面を開いただけでは BeforeCreate は呼ばれません。

更新の名前を単に置き換えるだけでなく、ID が確定する位置が異なります。作成後のレコード ID を拡張 SQL で使うなら OnCreated を選びます。OnCreating の ID プレースホルダーは 0 です(Rds.cs)。

作成の入力反映・検証は ResultUtilities.Create、保存前フックと INSERT の準備は ResultModel.Create、保存後の SQL とフックは 同メソッドの後半で確認できます。

フォームを開いたとき・送信したとき

フォームは forms コントローラを使います。通常の新規作成画面と同じ new、通常の作成と同じ create という操作名なので、フォームだけを対象にする場合は Controller も確認します。

フォームを開く

操作手順は「フォーム機能で発行した URL を開く」です。公開期間内で、かつテナントのフォーム登録数が上限に達していなければ、FormsController.New が ItemModel.New を呼び、記録テーブルの EditorNew に進みます。

既存レコードを開く操作ではないので、標準の新規フォーム表示に「保存済みの送信レコードを読む段階」はありません。入力反映時に計算式処理を通ることと、作成フックをまだ通らないことを分けて考えます。参照コピーなどの追加条件はこの図から除いています。登録数の上限に達している場合は、図の途中で上限超過の画面を返し、以降の段階へは進みません(送信時も同様に、作成処理の前に上限超過のエラーを返します)。

根拠は FormsController.New、ItemModel.New、EditorNew、新規モデルの入力反映です。

フォームを送信する

操作手順は「フォームに入力して送信する」です。FormsController.Create は公開期間、CAPTCHA、フォーム登録数の上限を順に検証した後に ItemModel.Create を呼びます。送信に成功すると、登録数のカウントを加算します。以降の作成フックは、先ほどの新規作成の図と同じ順です。ただし Controller は forms、Action は create です。

送信完了画面は別のリクエストです。thanks はサイト設定を読み込んで完了メッセージを描画し、新たにレコードを作成しません。そのため AfterCreate が「送信完了画面を開いたとき」の条件になるわけではありません。また、完了画面の経路は通常のエディタ描画を通らないので、そのメッセージ描画に BeforeOpeningPage は使いません(FormsController.Create・Thanks、送信成功時の応答、ItemModel.FormThanks)。

Controllers を items に限定した拡張サーバースクリプト・拡張 SQL は、フォームの forms リクエストには一致しません。通常画面では動いてフォームで動かない場合、実行フックに加えて適用対象の絞り込みも確認します。

目的から条件を選ぶ

やりたいこと 条件・絞り込みの選び方
一覧の取得条件を変える SS の WhenViewProcessing。初回の items/index と行再取得の items/gridrows を考慮する
一覧の行ごとに表示を調整する SS の BeforeOpeningRow
編集画面を初めて開くときに表示を調整する SS の BeforeOpeningPage と items/edit
新規画面・フォームの初期表示を調整する SS の BeforeOpeningPage と new。通常画面とフォームは Controller で分ける
計算式へ渡す値を調整する SS の BeforeFormula。保存専用と考えず、呼び出し元の操作も確認する
保存するモデルの値を作成・更新前に変更する SS の BeforeCreate・BeforeUpdate。標準検証との前後関係に注意する
保存後の処理を行う SS の AfterCreate・AfterUpdate。同じリクエストで再取得も起こることを考慮する
DB に作成された ID を使って SQL を流す 拡張 SQL の OnCreated
フォーム送信だけに処理を適用する forms/create と BeforeCreate または AfterCreate。SQL なら OnCreating または OnCreated

モデルの値を変える場合も、表示用の評価とDB保存を区別します。通常の更新で保存前のモデルを変更するなら BeforeUpdate、入力途中の表示を評価し直すなら BeforeOpeningPage というように、ここまでの呼び出し順に合わせて置き場所を選びます。

自分の設定で確認するときの手順

ここまでの図はソース上の順序です。実機で確認するときは、テスト用の記録テーブルを使い、次の手順でリクエストと条件を照合します。

  1. テーブルの管理のサーバースクリプトで、調べる条件を選びます。まずは BeforeOpeningPage、BeforeOpeningRow、BeforeCreate・AfterCreate、BeforeUpdate・AfterUpdate を操作ごとに確認します。
  2. context.Log を使う既存のログ出力に Condition・Controller・Action と、拡張側かサイト側かを区別できる名前を含めます。まず1つの条件で記録し、次に同じ操作の前後の条件を追加すると、ログの順序を比較しやすくなります。
  3. ブラウザの開発者ツールの Network を開き、一覧を開く → 既存レコードを開く → 更新する → 新規画面を開く → 作成する、の順に操作します。
  4. フォーム URL を開き、送信します。forms/new、forms/create、成功後の forms/thanks を別のリクエストとして確認します。
  5. スクリプトの実行を記録したログは、リクエストごとに区切って読みます。次の表と照合し、追加取得・再計算で同じ条件が増えていないかも見ます。
操作 重点的に照合する組み合わせ
一覧を開く index と BeforeOpeningPage、index と各行の BeforeOpeningRow
既存レコードを開く edit と WhenloadingRecord、edit と BeforeOpeningPage
更新する update と BeforeUpdate・AfterUpdate、再描画経路の update と BeforeOpeningPage
新規画面を開く new と BeforeOpeningPage。BeforeCreate はまだ呼ばれない
作成する create と BeforeCreate・AfterCreate
フォームを開く forms・new と BeforeOpeningPage
フォームを送信する forms・create と BeforeCreate・AfterCreate

context.Log はブラウザのコンソールではなく、サーバー側の LogBuilder に追加します(ServerScriptModelContext.cs)。拡張 SQL の実行は SS のログだけでは観測できないので、DB 側の実行ログとソース上の呼び出し箇所も照合します。

呼び出し回数を固定して考えない

  • WhenloadingRecord は、画面を最初に開くときだけでなく、保存後の再取得でも呼ばれます。OnCreated・OnUpdated がある場合の追加再取得もあります。
  • 計算式処理は入力反映の中で呼ばれます。SetByFormData と SetByForm の両方に呼び出しがあるため、BeforeFormula・AfterFormula を「保存1回につき各1回」と扱えません(SetByFormData の末尾、SetByForm の末尾側)。
  • WhenViewProcessing は View インスタンスごとに実行済みを記録します。新しいビューで取得し直す場合は再び呼ばれます(View.cs)。
  • 権限・入力・CAPTCHA などの検証で途中終了した場合、後続の保存フックまで到達しません。

まとめ

一覧の取得条件は WhenViewProcessing、行の表示調整は BeforeOpeningRow、編集画面の表示調整は BeforeOpeningPage が起点です。作成・更新では、サーバスクリプトと拡張 SQL の前後の条件を、入力反映・検証・DB保存の順序に合わせて確認します。

同じ BeforeOpeningPage でも、初回の edit と保存後の update は別の操作です。フォームも forms/new と forms/create を分けて読み、条件名と Controller・Action を組み合わせると、対象の処理を選びやすくなります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?