Oracle ApexでCRUD画面を爆速開発 - その3（登録/更新処理,Validation,アクセス制限など）



# シリーズ
[Oracle ApexでCRUD画面を爆速開発 - その1（構成周り、一覧表示）](https://qiita.com/harukb/items/bad041174f59a9f07141)
[Oracle ApexでCRUD画面を爆速開発 - その2（詳細表示）](https://qiita.com/harukb/items/d4996b5a9a11ee2f3165) 
[Oracle ApexでCRUD画面を爆速開発 - その3（登録/更新処理,Validation,アクセス制限など）](https://qiita.com/harukb/items/f63c9035de34282320d6) //今回
[Oracle ApexでCRUD画面を爆速開発 - その4（選択リストの内容で一覧表示内容を更新させる）](https://qiita.com/harukb/items/7b86706f010f886b89f0) 

# 前回の内容
詳細画面を作成し、一覧画面からの遷移処理を実装しました。

# 今回の主な内容
- INSERT,UPDATE,DELETE処理を作成する
- ボタンの表示ON/OFFを状態によって切り替える
- グローバル変数からログインユーザ名を表示する
- Validationを作成する
- ページへのアクセス制限をかける
- リスト表示の対象フィルタリング


# INSERT,UPDATE,DELETE処理を作成する
## CREATEボタンを作成
1 "PageDesigner">"Layout"にてデフォルトのSUBMITボタンを削除する

2 上記に続けて、CREATEボタンをドラッグして作成する
- "Button Name"→"CREATE"
- "Label"→"登録"
- "Behavior"→"Submit Page"

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/307faccb-308f-fc17-918b-2ff2f159f971.png)|
|:-:|

## CREATEボタンの処理を実装
"Page Processing"にてCREATEボタンの処理を実装します。

1 "Processes"の+ボタンをクリック

2 "Name"に"ins_emp"、"Type"に"PL/SQL"、"Source"の"PL/SQL"としてINSERT用のFUNCTIONを呼び出す下記の処理を記述します。

`#OWNER#.EMP_PKG.INS_EMP(
 　P_EMPNO => :P3_EMPNO,
 　P_ENAME => :P3_ENAME,
 　P_JOB => :P3_JOB,
 　P_MGR => :P3_MGR,
 　P_HIREDATE => TO_DATE(:P3_HIREDATE,'YYYY/MM/DD'),
 　P_SAL => :P3_SAL,
 　P_COMM => :P3_COMM,
 　P_DEPTNO => :P3_DEPTNO
);`

3 成功、エラー時のメッセージを入力します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/6ea409fe-8bec-cd1a-4e21-12dc98cbc043.png)|
|:-:|

## CREATEボタン処理後の遷移を実装

1 "Branches"の+ボタンより処理を追加する。

- "Name"→"GoToPage2ByInsert"
- "Behavior"の"Type"→"Page or URL(Redirect)"
- "Behavior"の"Target"→(ダイアログにて)Page→"一覧画面(ここではPage2)"を選択
- "Behavior"の"Target"→(ダイアログにて)ClearSessionStateの"Clear Cache"→"詳細画面(ここではPage3)"を選択
- "Server-side Condition"の"When Button Pressed"→"CREATE"を選択

2 実行し、詳細画面にて従業員情報を入力し"登録"をクリック。登録が成功し一覧画面に戻ることを確認。
おめでとうございます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/cf3fd418-c9ed-b2a1-24aa-449f87bd1cbd.png)|
|:-:|

## UPDATEボタンを作成
CREATEボタンの隣にUPDATEボタンを作成。

- "Button Name"→"UPDATE"
- "Label"→"更新"
- "Behavior"→"Submit Page"

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/215bede4-f6dd-014d-c14a-bde61e28bccc.png)|
|:-:|

## UPDATEボタンの処理を実装
"Page Processing"にてUPDATEボタンの処理を実装します。

1 "Processes"の+ボタンをクリック

2 "Name"に"upd_emp"、"Type"に"PL/SQL"、"Source"の"PL/SQL"としてUPDATE用のFUNCTIONを呼び出す下記の処理を記述します。

`#OWNER#.EMP_PKG.UPD_EMP(
　P_EMPNO => :P3_EMPNO,
　P_ENAME => :P3_ENAME,
　P_JOB => :P3_JOB,
　P_MGR => :P3_MGR,
　P_HIREDATE => TO_DATE(:P3_HIREDATE,'YYYY/MM/DD'),
　P_SAL => :P3_SAL,
　P_COMM => :P3_COMM,
　P_DEPTNO => :P3_DEPTNO);`

3 成功、エラー時のメッセージを入力します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/91e94994-b6bc-f6ca-572c-f043ed64ff3b.png)|
|:-:|

## UPDATEボタン処理後の遷移を実装

1 "Branches"の+ボタンより処理を追加する。

- "Name"→"GoToPage2ByUpdate"
- "Behavior"の"Type"→"Page or URL(Redirect)"
- "Behavior"の"Target"→(ダイアログにて)Page→"一覧画面(ここではPage2)"を選択
- "Behavior"の"Target"→(ダイアログにて)ClearSessionStateの"Clear Cache"→"詳細画面(ここではPage3)"を選択
- "Server-side Condition"の"When Button Pressed"→"UPDATE"を選択

2 実行し、一覧画面から従業員情報を選択し遷移された当画面で"更新"をクリック。更新が成功し一覧画面に戻ることを確認。
おめでとうございます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/9bc12872-8106-09c2-8fc5-0b1d036a0dee.png)|
|:-:|

## DELETEボタンを作成
1 上記に続けて、DELETEボタンをドラッグして作成する
- "Button Name"→"DELETE"
- "Label"→"削除"
- "Behavior"→"Submit Page"

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/c9dcc1de-2aac-0c8f-7af0-8c47bc81d590.png)|
|:-:|

2 DELETEボタンの背景色を変更する
"Appearance"の"Appearance"をクリックして修正
- "Type"→"Danger"

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/94450ef7-5ef9-a48a-fb3a-7394766a32d6.png)|
|:-:|

このような背景になります。（配置の良しあしはさておき）

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/46d653fe-308f-1ec5-6166-afdee81d4409.png)|
|:-:|

## DELETEボタンの処理を実装
"Page Processing"にてDELETEボタンの処理を実装します。

1 "Processes"の+ボタンをクリック

2 "Name"に"del_emp"、"Type"に"PL/SQL"、"Source"の"PL/SQL"としてDELETE用のFUNCTIONを呼び出す下記の処理を記述します。

`#OWNER#.EMP_PKG.DEL_EMP(
P_EMPNO => :P3_EMPNO);`

3 成功、エラー時のメッセージを入力します。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/afcdcfab-af8e-44eb-9af0-cde1a59679ac.png)|
|:-:|

## DELETEボタン処理後の遷移を実装

1 "Branches"の+ボタンより処理を追加する。

- "Name"→"GoToPage2ByDelete"
- "Behavior"の"Type"→"Page or URL(Redirect)"
- "Behavior"の"Target"→(ダイアログにて)Page→"一覧画面(ここではPage2)"を選択
- "Behavior"の"Target"→(ダイアログにて)ClearSessionStateの"Clear Cache"→"詳細画面(ここではPage3)"を選択
- "Server-side Condition"の"When Button Pressed"→"DELETE"を選択

2 実行し、一覧画面から従業員情報を選択し遷移された当画面で"削除"をクリック。削除が成功し一覧画面に戻ることを確認。
おめでとうございます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/9a75ebf9-69ce-2a1b-0f54-2a3228b6c4d9.png)|
|:-:|

## CANCELボタン処理後の遷移を実装
※下記を参考にCANCEL時の遷移処理も他のボタンに揃えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/5638999f-9f34-bcd1-e1b2-b926ffde049b.png)|
|:-:|

# 一覧画面を表示した際にセッション上に残る詳細画面のアイテムを消す
※消しておかないと画面遷移の順番によっては新規での詳細画面表示時に前回のEMPNOがセットされるため消しておきます。

1 "Page Rendering">"Processes"でプロセス追加
2 以下のように値を設定する

- "Identification">"CLEAR_P3ITEM",Type -> "Clear Session State"
- "Settings">"Type" -> "Clear all item on Page(s)","Page(2)" -> 3(詳細画面)

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/5324d96e-9120-77de-ca15-c3ec78a900a1.png)|
|:-:|


# ボタンの表示/非表示の切り替えを設定する
画面の状態（新規 OR 更新）に応じてボタンの表示を切り替えます。

判断方法：新規or更新はページロード時に（P2からセットされた）P3_EMPNOの値がnullか否かで判断する
条件とアクション：
- 新規の場合→削除、更新ボタンを非表示　／登録ボタンを表示
- 更新の場合→登録ボタンを非表示＆P3_EMPNOを変更不能(PKのため)　／削除、更新ボタンを表示

1 左ペインの"DinamicActions"にて"Events">"PageLoad"を右クリックして"Create Dynamic Action"を実行

2 上記の考えを基に以下の判断方法を設定する

- "Identification">"Name"→"isCreate"
- "When">"Event"→"Page Load"
- "Client-side Condition">"Type"→"Item is null" ,"Item"→"P3_EMPNO"

3 新規の場合の設定を行います。
左ペインの"isCreate"のTrueを右クリックして、"Create TRUE Action"を実行する

4 Actionを作成し以下を設定する
(１個目のAction) DELETEボタンの非表示

- "Identification">"Action"→"Hide"
- "Affected Elements">"Selection Type"→"Button","Button"→"DELETE"

(２個目のAction) UPDATEボタンの非表示

- "Identification">"Action"→"Hide"
- "Affected Elements">"Selection Type"→"Button","Button"→"UPDATE"

5 更新の場合の設定を行います。
左ペインの"isCreate"のFalseを右クリックして、"Create FALSE Action"を実行する 

(１個目のAction) CREATEボタンの非表示

- "Identification">"Action"→"Hide"
- "Affected Elements">"Selection Type"→"Button","Button"→"CREATE"

(２個目のAction) Empno（P3_EMPNO）の変更不能

- "Identification">"Action"→"Disable"
- "Affected Elements">"Selection Type"→"Item(s)","Item"→"P3_EMPNO"

6 実行して詳細画面のボタン表示とEmpNoのマスクが切り替わることを確認出来たら成功です。


(更新の場合)

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/664045a8-9302-8a8c-448a-a93d65df6b06.png)|
|:-:|


# グローバル変数からログインユーザ名を表示する
用意されているグローバル変数より様々な値を簡単に参照することが可能です。
[グローバル変数](https://docs.oracle.com/cd/F16840_01/aeapi/Global-Variables.html#GUID-5164592B-6864-4E2B-8DE3-64B463687A41)

## 一覧画面にログインユーザーを表示する
1 "Display Only"項目を上部に作成する


|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/846104d1-21a2-00ae-1145-389486654659.png)|
|:-:|

2 "DEFAULT"項目に"&APP_USER."を入力する

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/9bf32f9c-8c39-558a-5296-92a19b4678b5.png)|
|:-:|

3 実行して一覧画面の上部にログインユーザーが表示されることを確認できたら成功です。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/ebcdb06f-0653-3b15-3558-b6c69ad00701.png)|
|:-:|

# Validationを作成する
サンプルとして入力文字チェックを詳細画面の一部の項目にかけてみましょう
※必須チェックは各項目の"PageItem">"Validation"での設定でも可能ですが、整理のしやすさからここでまとめています。
※ここではDBアクセスがありませんが、PL/SQLでのDB突き合わせチェックも可能です。

**ルール1：Empnoは必須入力かつ半角数字のみであること 
ルール2：Enameは必須入力かつ10バイト未満であること**
（実際にはバイト数で言われたら不親切なのは置いておきます）

1 （ルール1の必須入力設定）"Processing">"Validations"を右クリックしてValidationを作成する

- "Identification">"NAME"→"EMPNO_Required"
- "Validation">"Type"→"Item is NOT NULL","item"→"P3_EMPNO"
- "Error">"ErrorMessage"→"Empnoは必須項目です。","Associated Item"→"P3_EMPNO"

2 （ルール1の半角数字設定）上記と同じ手順で追加のValidationを作成する

- "Identification">"NAME"→"EMPNO_Numeric"
- "Validation">"Type"→"Item is numeric","item"→"P3_EMPNO"
- "Error">"ErrorMessage"→"Empnoは数字（0から9）のみ有効です。","Associated Item"→"P3_EMPNO"

3 （ルール2の必須入力設定）上記と同じ手順で追加のValidationを作成する

- "Identification">"NAME"→"ENAME_Required"
- "Validation">"Type"→"Item is NOT NULL","item"→"P3_ENAME"
- "Error">"ErrorMessage"→"Enameは必須項目です。","Associated Item"→"P3_ENAME"

4 （ルール2の10バイト入力設定）上記と同じ手順で追加のValidationを作成する

- "Identification">"NAME"→"ENAME_Length10"
- "Validation">"Type"→"PL/SQL Function Body Returning Boolean"

PL/SQLコード
`if lengthb( :P3_ENAME ) <= 10
then
  return true;
else
  return false;
end if;`

- "Error">"ErrorMessage"→"Enameは最大10バイトで入力してください。","Associated Item"→"P3_ENAME"

5 実行して詳細画面で更新ボタンもしくは登録ボタンにより上記のValidationがかかることを確認できたら成功です。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/5578cbff-7d77-d0a7-3036-27f680d89cd3.png)|
|:-:|

# リスト表示の対象フィルタリング
リスト表示の対象制限を行いたい場合はWHERE句を利用します。ログインユーザー情報を基にした動的な条件でも、前述のグローバル変数を用いれば簡単に実現できます。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/6eabe149-11d0-6a1a-d88a-da414de269f8.png)|
|:-:|


**※ グローバル変数の呼び出し方の違いに注意**

- UIへの設定　"&APP_USER."
- SQLへの埋め込み:APP_USER"

1 中央の"Component View">"Page Rendering">"Content Body">"V_Emp"をクリック
2 左ペインより"Source">"Where Clause"に"ENAME = :APP_USER"を入力

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/19963996-e590-ec87-98f2-2a9ece6086ab.png)|
|:-:|
 
3 一覧画面を実行してフィルターがかかったら成功です。


# ページへのアクセス制限をかける
Oracle Apexアプリケーションアカウントを利用した認証を行う場合、以下の「認証スキーム」を利用して簡単にログインユーザーの存在チェック結果によって特定の画面を表示させないことが可能です。
認可認証については公式ドキュメントを読んでおきましょう　[公式ドキュメント](https://docs.oracle.com/cd/E99982_01/HTMDB/establishing-user-identity-through-authentication.htm)

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/88435a40-61f7-66c1-beeb-864d40f0f4d2.png)|
|:-:|

※PL/SQLでのグローバル変数は上記の2個とも呼び出し方が違うのでまた注意（APEX_APPLICATION.G_USER）

1 "Shared Components">"Authorization Scheme"で存在チェックのPL/SQLを設定する

- "Name" →　"ISUSER"
- "Authorization Scheme">"Scheme Type" →　"PL/SQL Function Returning Boolean"
- 上記>"PL/SQL Function Body"にて例えば以下のPL/SQLを設定

`DECLARE
　CNT NUMBER(1,0);
　b BOOLEAN;
BEGIN
　SELECT COUNT(ENAME) INTO CNT FROM EMP WHERE ENAME = APEX_APPLICATION.G_USER;
　　if CNT > 0 then
　　　return true;
　　else
　　　return false;
　　end if;
END;`

- "Identify error message ">"ユーザーがマスタに存在しません。"


2 Page側で作成した制御を設定
"Page Designer">対象のページ（左ペインのルート）をクリックして"Page"を表示する。

3 以下のように"Security">"Authorization Scheme"に作成済の"ISUSER"を設定

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607651/b72de060-3862-4318-841a-37d184c90784.png) |
|:-:|

4 実行してユーザーのマスタ設定状態により画面表示しようとしてもエラー表示が出て入れないことを確認できたら成功です。