LoginSignup
0
0

More than 1 year has passed since last update.

【RAP】Actionを追加する

Last updated at Posted at 2021-12-24

はじめに

この記事ではRAP(ABAP RESTful Application Programming Model)のActionを実装します。Actionとは、標準で実装されるCRUD以外で、ビジネスオブジェクトの値を変更するために定義するものです。

シリーズの先頭はこちら☞ 【RAP】ADTのRAP Generatorを使ってみる

シナリオ

こちらの記事で生成したビジネスオブジェクトに、以下の機能を追加します。

  1. Actionを使ってステータスを変更
  2. Actionの有効/無効の制御

1. Actionを使ってステータスを変更

ビジネスオブジェクトにStatusという項目を追加し、UIからステータスを変更するためのActionを実装します。

1.1. Status項目を追加

まず、テーブルにStatusの項目を追加します。

define table zperson_m {
  key client            : abap.clnt not null;
  key person_uuid       : sysuuid_x16 not null;
  first_name            : abap.char(100);
  last_name             : abap.char(100);
  email                 : ze_email120;
  birthday              : abap.dats;
  status                : abap.char(1); //追加
  ...

}

画面に項目が表示されるよう、Interface ViewおよびConsumption Viewにも追加します。

ZI_PERSON_M
{
  key person_uuid as PersonUUID,
  @EndUserText.label: 'First Name'
  first_name as FirstName,
  @EndUserText.label: 'Last Name'  
  last_name as LastName,
  @EndUserText.label: 'Email' 
  email as Email,
  @EndUserText.label: 'Birthday'
  birthday as Birthday,
  @EndUserText.label: 'Status' //追加
  status as Status,
  ...
}
{
  key PersonUUID,
  FirstName,
  LastName,
  Email,
  Birthday,
  Status, //追加
  LocalLastChangedAt  
}

また、Behavior Definitionのマッピングにも追加します。これを忘れていたことで、アクションのボタンを押して、ロジックが通っても項目に反映されませんでした!

  mapping for ZPERSON_M
  {
    PersonUUID = PERSON_UUID;
    FirstName = FIRST_NAME;
    LastName = LAST_NAME;
    Email = EMAIL;
    Birthday = BIRTHDAY;
    Status = STATUS; //追加
    CreatedBy = CREATED_BY;
    CreatedAt = CREATED_AT;
    LastChangedBy = LAST_CHANGED_BY;
    LocalLastChangedAt = LOCAL_LAST_CHANGED_AT;
    LastChangedAt = LAST_CHANGED_AT;
  }

1.2. ドラフトテーブルを再生成

テーブルに項目を追加したので、ドラフトテーブルにも追加する必要があります。マニュアルで追加もできますが、Behavior DefinitionからQuick Fixでドラフトテーブルを再生成できます。

ドラフトテーブルにカーソルを合わせ、Ctrl + 1(Quick Fix)を実行します。
image.png
"Recreate draft table ..."というオプションが出てくるのでそれを選択します。
image.png
ドラフトテーブルが開きます。項目が追加されていることを確認し、有効化します。
image.png
※有効化したとき、以下のようなエラーが出ました。
image.png
原因は、再生成したときに"client"の項目が"mandt"に変わったためでした。"client"に直したところ、有効化できました。

1.3. Behavior DefinitionでActionを定義

Behavior Definitionに以下のコードを追加します。

  determination set_email on save {create; }
  validation mandatory_check on save {create; update; field FirstName, LastName; }

  action set_complete result [1] $self; //追加

Actionの構文
Actionの構文は以下のようになります。以下は通常のAction場合で、このほかに新規インスタンスを作るためのFactory Actionというものもありますが(コピーなどで使う)、ここでは割愛します。

[ internal][static] action
                  [(
                  [features: {instance | global}]
                  [precheck]
                  [ authorization:none]
                  [ authorization:update]
                  [lock:none]
                   )]
                   ActionName [external 'ExternalName']
                  [ InputParameter]
                  [ OutputParameter];

参考:CDS BDL - action

オプションの説明

項目 説明
internal "internal"とつけるとそのアクションはODataからではなくDeterminationやActionなどのロジックの中からだけアクセスできる
static デフォルトで、アクションはBOのインスタンスにひもづいている(Bound Action)。"static"とつけるとそのアクションは特定のインスタンスにはひもづかなくなる(Unbound Action)
features アクションの有効/無効をどのようにコントロールするかを指定する。instance:インスタンスごとに有効/無効をコントロール。global: 外部的な要因により有効/無効をコントロール(例:季節や時間帯など)
precheck リクエストがtransactional bufferに届く前にチェックを実行する
authorization:none Behevior definiitonでauthorization masterを指定した場合、アクションは基本的に権限チェックの対象になるが、この設定をすると権限チェックの対象外になる
authorization:update 当該アクションに対してupdateのときと同じチェックを行う
lock:none インスタンスレベルのアクションは対象のエンティティをロックするが、この設定をするとロックされない
external ODataのメタデータで使用するためのアクションの名前。指定しない場合はもともとのアクション名が使用される
InputParameter アクションに渡すインプットパラメータ。指定可能値はヘルプを参照
OutputParameter アクションからの返り値。キーワードresultの後に指定する。カーディナリティは次の4通り:[0..1], [1], [0..*], [1..*] 詳細はヘルプを参照 

1.4. Behavior ImplementationでActionを実装

Quick Fixでset_completeメソッドをBehaviro Implementationに追加し、以下のように実装します。

      set_complete FOR MODIFY
            IMPORTING keys FOR ACTION Person~set_complete RESULT result.

1. ステータスを更新
処理対象のインスタンスのStatusを更新します。

    "update status
    MODIFY ENTITIES OF zi_person_m IN LOCAL MODE
      ENTITY Person
        UPDATE FIELDS ( Status )
        WITH VALUE #( FOR key IN keys ( %tky = key-%tky
                                        Status = 'C' ) ). "Complete

ドキュメント:MODIFY ENTITY, ENTITIES

2. 更新したエンティティを返す
更新後のエンティティを読み込み、resultに設定します。

    "read changed data for action result
    READ ENTITIES OF zi_person_m IN LOCAL MODE
      ENTITY person
        ALL FIELDS WITH
        CORRESPONDING #( keys )
        RESULT DATA(persons).

    result = VALUE #( FOR person IN persons ( %tky = person-%tky
                                              %param = person ) ).

ドキュメント:READ ENTITY, ENTITIES

resultの構造は以下のようになっており、%paramがpersonの構造と対応しています。
image.png

1.5. Behavior ProjectionでActionを定義

UIからアクションを使えるようにするには、Behavior Projectionにもアクションを定義する必要があります。
image.png
以下のように、use action ...で追加します。

projection;
strict;
use draft;

define behavior for ZC_PERSON_M alias Person
use etag

{
  use create;
  use update;
  use delete;

  use action Edit;
  use action Activate;
  use action Discard;
  use action Resume;
  use action Prepare;

  use action set_complete; //追加
}

1.6. Metadata ExtensionでActionを追加

最後に、Metadata ExtensionにUIアノテーションを追加し、アクションがUIに表示されるようにします。FirstNameについている@UI.lineItemアノテーションに以下を追加します。実は対象の項目はどれでもよいのですが、今回は一番先頭の項目にしました。

 { 
    type:#FOR_ACTION,
    dataAction: 'set_complete',
    label: 'Set Complete'    
  }

全体では以下のようになります。

  @UI.lineItem: [ {
    position: 10 , 
    importance: #MEDIUM
  },{ 
    type:#FOR_ACTION,
    dataAction: 'set_complete',
    label: 'Set Complete'    
  } ]
  @UI.identification: [ {
    position: 10 
  } ]
  FirstName;

ステータスが一覧から見えるように、Statusの項目を追加しておきます。

  @UI.lineItem: [ {
    position: 50 , 
    importance: #MEDIUM
  } ]  
  Status;

1.7. 動作確認

テーブルの上に"Set Complete"というボタンが追加されます。
image.png

ボタンを押すとStatusに'C'が設定されます。
image.png

2. Actionの有効/無効の制御

続いて、すでに完了になっているレコードを選択した場合は"Set Complete"を押せないように、アクションの有効/無効を制御します。

2.1. Behavior Definitionの設定

Actionの定義に( features: instance )を追加します。これで、アクションの有効/無効をインスタンスごとに判断できるようになります。

  action ( features: instance ) set_complete result [1] $self;

ドキュメント:Dynamic Feature Control: Actions

2.2. Behavior Implementationの実装

Behavior Implementationに以下のメソッドを追加します。Quick Fixがきかなかったので、マニュアルで追加しました。

CLASS lcl_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.
    ...

    METHODS get_features FOR FEATURES IMPORTING keys REQUEST requested_features FOR Person RESULT result.     

ENDCLASS.

CLASS lcl_handler IMPLEMENTATION.

  METHOD get_features.
  ENDMETHOD.
...

メソッドget_featuresを以下のように実装します。

  METHOD get_features.
    READ ENTITIES OF zi_person_m IN LOCAL MODE
    ENTITY person
      FIELDS ( Status )
      WITH CORRESPONDING #( keys )
      RESULT DATA(persons).

    result = VALUE #( FOR person IN persons (
                        %tky = person-%tky
                        %action-set_complete = COND #( WHEN person-Status = 'C'
                                                       THEN if_abap_behv=>fc-o-disabled
                                                       ELSE if_abap_behv=>fc-o-enabled )
                     ) ).

  ENDMETHOD.

まずは、いつものようにREAD ENTITIESで処理対象のレコードを取得します。取得したテーブル(実際には1行)をループし、resultに結果を設定します。デバッグで見ると、resultsは以下の項目を持っています。featureコントロールはアクションだけでなく項目制御にも使え、resultsの構造はコントロールする対象によって変わります。
image.png

%action-<アクション名>の項目にdisabled/enabledを設定するときに、CONDという命令を使ってコンパクトに書いていますが、if~elseを使っても書くことができます。以下の1と2は同じ意味です。

  "1
  isEnabled = COND #( WHEN person-status = 'C'
                           THEN abap_false
                           ELSE abap_true ).

  "2                           
  if person-status = 'C'.
    isEnabled = abap_false.
  else.
    isEnabled = abap_true.
  endif.  

2.3. 動作確認

ステータス'C'が設定された行を選択すると、アクションが有効になりません。
image.png
ステータスが未設定の行を選択すると、アクションが有効になります。
image.png
複数行選択したときは、有効な行が1行でもあればアクションは有効になります。
image.png

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