Pleasanterのサーバスクリプト活用例(2024年編)

## はじめに
プリザンターはあらゆる業務アプリを基本機能だけでも作成することができます。
しかし、使っていくとだんだん「こういう機能が欲しいな～」、「こういう制御をしたいな」といったやりたいことが広がっていきます。
そんな時はサーバスクリプトを使うことで「やりたいこと」が実現できるかもしれません。
ということで、今回はサーバスクリプトについて便利な使い方をいくつか記事にしようと思います！

## サーバスクリプト-基礎-
早速ですが、みなさま、サーバスクリプトは使っていますか？
すでにバリバリ使っていただいている方も、これから使ってみようかな？と考えている方も。使ったことのない方もいると思います。
まずはサーバスクリプトとは何なのか、どういう機能なのかについておさらいです。

- サーバスクリプトはJavaScriptで処理を記述する
- サーバサイドで実行し、条件分岐、計算、文字列処理、レコード
の操作、メールやチャットへの通知、動的なアクセス制御等を行
うことが可能な機能

上記2つを理解していただければまず最初のステップはOKです。

### スクリプトとの違い
サーバスクリプトを使用している方の中には、スクリプトとどう違うのか？と疑問に思う方もいると思います。
この章では、サーバスクリプトとスクリプトの違いについてまとめてみました。
|  |サーバスクリプト|スクリプト|
|:-:|:-:|:-:|
|実行環境|サーバー側で動作|クライアント側で動作|
|エラー発生時の挙動|適切なエラーハンドリングをしていない場合はアプリケーションエラーとなる|該当のスクリプトは動作しないがアプリケーションエラーにならない|
|ソースコードの閲覧|「テーブルの管理」でのみソースコードの閲覧が可能|ブラウザの開発者ツール上で、ソースコードを閲覧することが可能|

サーバスクリプトを使用することで下記のクレデンシャル情報を隠すことができるため、スクリプトと比較するとよりセキュアです。
- APIキー
- 各種ID
- 個人情報
- その他権限のないユーザに秘匿する必要がある情報

## サーバスクリプトの条件
続いては、「サーバスクリプトの条件」について解説いたします。
とはいえ、条件自体にどういったものがあるのかについては公式のマニュアルがありますのでそちらをご確認ください。
[開発者向け機能：サーバスクリプト：条件](https://pleasanter.org/ja/manual/server-script-conditions)
この章では基本的な動作（画面表示時、新規作成、更新）にどういった条件が有効なのか、またその調べ方について解説します。

### 一覧画面表示時
一覧画面表示時には以下の条件が使用可能です。
- サイト設定の読み込み時
- ビュー処理時
- レコード読み込み時
- 画面表示の前
- 行表示の前

### 新規作成時
新規作成時には以下の条件が使用可能です。
- サイト設定の読み込み時
- ビュー処理時
- レコード読み込み時
- 計算式の前
- 計算式の後
- 作成前
- 作成後
- 画面表示の前

### 更新時
更新時には以下の条件が使用可能です。
- サイト設定の読み込み時
- ビュー処理時
- レコード読み込み時
- 計算式の前
- 計算式の後
- 更新前
- 更新後
- 画面表示の前

上記で挙げた動作のほかにも、プロセスボタンの処理時や、インポート時、エクスポート時、などサーバスクリプトのトリガーはあらゆる場所に存在します。
これらは以下のようなログを仕込むことで確認が可能です。
```context.Log(context.Condition)```
サーバスクリプトを使用する際は、ぜひログを仕込んでどの条件で動作するかを確認してみてください。

## サーバスクリプト活用例
ではここまで、サーバスクリプトの基本的な知識について解説してきました。
それでは実際に活用例を見ていきましょう。
ぜひご活用ください！

### 1.context
はじめはcontextオブジェクトについてです。
contextはすべてのサーバスクリプトの基礎といっても過言ではないほどあらゆる個所で多用します。
というのもcontextはユーザID、サイトIDなどの、ユーザ要求に関する情報を参照する際に使用します。
また、スクリプト間のデータ共有、ログ出力、メッセージ出力に使用します。
contextには多数のプロパティ及びメソッドが用意されています。詳しくは下記公式マニュアルをご確認ください。
[開発者向け機能：サーバスクリプト：context](https://pleasanter.org/ja/manual/server-script-context)
今回はcontextの中のActionというプロパティを使用して特定のトリガーでのみサーバスクリプトを動かします。

条件を「画面表示の前」にしている場合、基本的には一覧画面表示時や編集画面表示時など画面を表示した際にサーバスクリプトは動作します。
しかし、サーバスクリプトによっては編集画面の時だけでいいのに....となることがありますよね？
そんなときはcontext.Actionで条件を指定することができます。
```javascript
//画面表示時にログを出力する処理
if(context.Action === 'edit'){
  context.Log("サーバスクリプトが動作しました。")
}
```
- 一覧画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/57c2a732-9c4c-00ce-729e-d3e1e312eeff.png)

- 編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/6041c320-089d-fc1c-6619-c75fa996822e.png)

このようにcontext.Actionで"edit"を指定したことにより、編集画面でのみ動作させることができます。
context.Actionの指定がわからない！という方は画面表示時などに```context.Log(context.Action)```を設定することで今どんなActionが動作したかを確認することが可能です。

### 2.model
続いてはmodelオブジェクトについて解説します。
modelはサーバスクリプトで使用可能な現在の「レコード」の情報をもつオブジェクトです。
プロパティを使用し項目の値の読み取りが行えます。
プロパティに値を代入すると一覧画面やエディタの項目の表示を変更できます。
詳しくは下記の公式マニュアルをご確認ください。
[開発者向け機能：サーバスクリプト：model](https://pleasanter.org/ja/manual/server-script-model)
とはいえ、modelオブジェクトは使ったことがある方も多いのではないでしょうか？
なので、今回はmodelを使用する際の注意点についての解説です。

前述したようにmodelは現在の「レコード」の情報をもつオブジェクトです。
例えば編集画面表示時ClassA(分類A)に「りんご」と記入されているとします。
この際、model.ClassAは「りんご」です。
そのままClassAを「みかん」に書き換えたとします。
すると、model.ClassAは「みかん」になります。
つまりmodelは今現在記入されている値が取得できます。

ところで、下記のような要件を実装したいなと考えたことはないでしょうか。
__特定の項目が編集されているときのみ更新OKとしたい__
このような要件は必須入力の制御だけでは難しく、サーバスクリプトが必要です。
画面表示時の値を保持しておいて、更新時に比較できたらいいな～と考えたことはないでしょうか。
そんなときは```model === saved```比較を行うのがおすすめです！
現在の「レコード」の情報をもつmodelに対して、更新前の「レコード」の情報をもつオブジェクトがsavedです。
詳しくは下記の公式マニュアルをご確認ください。
[開発者向け機能：サーバスクリプト：saved](https://pleasanter.org/ja/manual/server-script-saved)
savedはmodelと異なり、更新前の「レコード」の情報を持ちます。つまりDBに登録されている値を参照するのがsavedです。
では実際にサーバスクリプトを設定してみましょう。
```javascript
//更新時に数値項目を比較する処理
if(saved.NumA === model.NumA) {
    context.Error('数値を編集してください。');
}
```
- 変更していない場合
下記のようにエラーメッセージが出現します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/843fe52e-d45e-fce9-cb0d-ab3bf64469dc.png)

- 変更した場合
問題なく更新が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/0c50eeee-d799-d5fd-4f58-17387ce66fb4.png)

このように```model === saved```比較を行うことで、入力チェックを実装することができます。

### 3.items
前の章で説明したmodelはあくまで今開いているレコードに対して項目の変更や読み取りを行いました。
では別のレコードに対して同様の処理を実施したい場合はどうすればいいのでしょうか？
そんなときはitemsを使用しましょう！
itemsはサーバスクリプトで「レコード」の作成、読み取り、更新、削除等を行うためのオブジェクトです。
「model」では現在のレコードのみを扱えますが、「items」ではIDを指定して任意のレコードを扱うことができます。
itemsは前述したように別のレコードやテーブルに対して操作を行うサーバスクリプトです。
そのため、数々のオプションが用意されています。
詳しくは下記公式マニュアルをご確認ください。
[開発者向け機能：サーバスクリプト：items](https://pleasanter.org/ja/manual/server-script-items)
今回はこの中からレコード作成後に作成したレコードIDを取得する方法について解説します。

itemsの中にはCreateメソッドがあります。このメソッドを使用することで特定の操作をしたタイミングでレコードを作成することが可能です。
しかし、作成したレコードはリンクしているわけではないため、無事に作成されたかがわかりませんし、どのレコードが作成されたものなのかわかりません。
ということでitems.Createでレコード作成後に作成したレコードIDを取得して元のレコードに記載する処理を実装しようと思います。

まずは以下のような構成のテーブルを用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/a8eb20b8-4b0c-fa28-3f0d-06c284f3eccf.png)
今回は記入用テーブルにレコードを作成した際、バックアップテーブルに「新規作成」というタイトルのレコードを作成します。
サーバスクリプトの都合上、バックアップテーブルの「サイト名」には「バックアップ」という名前を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/e7c129e0-f507-9b7f-35dc-80b95bdfb37b.png)

では記入用テーブルにサーバスクリプトを設定して試してみましょう。
条件は、「作成後」を指定します。
```javascript
//レコード作成後にレコードIDを取得して格納する
const siteId = items.GetClosestSite('バックアップ').SiteId;
const item = items.NewResult();
item.Title = '新規作成';
items.Create(siteId, item);
model.ClassA = item.ResultId;
model.UpdateOnExit = true;
```
- 記入用テーブルでレコードを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/a5d07d70-bb30-48ca-c731-cbeadd3c04a7.png)
分類AにIDが格納されていることがわかると思います。
IDは29358と書いてありますね

- バックアップテーブル
ではバックアップテーブルを確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3551590/f9532301-d347-bd41-d7e9-14e8912c694c.png)
記入用テーブルで確認した29358というIDのレコードが作成されていました！

このようにitemsはただレコードを作成、更新、削除するだけでなく操作したレコードの情報を持ちまわることも可能です。

## まとめ
いかがでしたか？
今回は使用頻度の高いサーバスクリプト(context,model,items)を使った活用例をまとめてみました！
まだサーバスクリプトを使ったことのない方は今回のサンプルをもとに新しいアプリを作成してみるのもいいかもしれません！
これらの活用例はまだまだ入り口で、もっと拡張性を持たせることも可能です。
標準機能で実装が難しいな～という壁にぶつかった際は、諦めるのではなく、一度サーバスクリプトの使用を検討いただけると幸いです！

また、プリザンターには年間サポートサービスがあります。
上記サーバスクリプトの使い方等、お問い合わせいただければお答えすることも可能ですので、ぜひこちらもよろしくお願いします！
[プリザンター｜年間サポートサービスのご紹介](https://pleasanter.org/support)