Practical Use of OOPs ABAP – Model View Controller (MVC). Part II

In Part I of MVC, we showed a practical example of ABAP program following the Model View Controller concept. Today, we would see how we can beautify and add more feature to the User Interface, i.e. in the View section of MVC.

Let’s work more with our User Interface today.

Scenario 2

Display Sales report with Layout and Toolbar Icons (filter Icon, Sort, Save layout icon etc )

Display Layouts means our User Interface, so we will be working with layout today i.e. our class CL_ALV (view).

In this case, we will NOT touch the data class CL_FETCH and selection class CL_SEL. We will only modify our class CL_ALV (View).

One of the most common requirements we get from our user is setting the layout, so we give parameter selection for user specific layout.

To meet this new requirement, we will create one more class (4th class for the report, 3 already created in the previous article) for this layout selection. As this is a very common requirement it is recommended to use a global class which will give us default layout and F4 help on layout and this global class can be reused across multiple developments. But here, I am using local class just to explain the concept.

4. Class for Layout Variant – CL_VARIANT:

Class CL_VARIANT will have two methods, F4_VARIANT and GET_DEFAULT.

F4_VARIANT: will return the list of layout present in this report.

GET_DEFAULT: will return the default layout which is a static method.

3. Class for Display – CL_ALV:

Our class CL_ALV definition has two References. One for CL_FETCH and other is for CL_VARIANT.

Needless to say, class CL_FETCH will provide the Business logic here and CL_VARIANT will provide us the layout to display.

CL_ALV class has three methods GET_OBJECT, LAYOUT_DIS, DISPLAY_ALV and CONSTRUCTOR.

CONSTRUCTOR: will hold the object of two classes CL_FETCH and CL_VARIANT.

GET_OBJECT: will return the object of the Factory method.

LAYOUT_DIS: will set Default layout and striped pattern.

DISPLAY: will display final result.

If you see method LAYOUT_DIS all layout functions are available here.

Methods DISPLAY_ALV will simply display the report.

Now we can call the methods in the events of Reports.

If you closely look at the report we are just modifying one class without disturbing the other class and this will give us the flexibility to modify the report view based on our requirement.

Full Program:

DATA : lv_vbeln TYPE vbap-vbeln .
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-000.
PARAMETERS : p_werks TYPE vbap-werks .
SELECT-OPTIONS : s_vbeln1 FOR lv_vbeln .
SELECTION-SCREEN END OF BLOCK b1 .
 
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-001.
PARAMETERS: p_vari LIKE disvariant-variant.
SELECTION-SCREEN END OF BLOCK b2 .
 
 
CLASS cl_variant DEFINITION.
  PUBLIC SECTION.
    TYPES : p_vari1 TYPE disvariant-variant.
    TYPES : g_repid TYPE sy-repid .
    DATA  : g_layout TYPE disvariant-variant .
    METHODS:  f4_variant CHANGING cv_layout TYPE disvariant-variant.
    CLASS-METHODS:  get_default CHANGING cv_layout TYPE disvariant-variant .
ENDCLASS .
*&---------------------------------------------------------------------*
*&       Class (Implementation)  VARIANT
*&---------------------------------------------------------------------*
*        Text
*----------------------------------------------------------------------*
CLASS cl_variant IMPLEMENTATION.
  METHOD f4_variant .
    DATA: ls_layout TYPE salv_s_layout_info,
          ls_key    TYPE salv_s_layout_key.
    ls_key-report = sy-repid.
    ls_layout = cl_salv_layout_service=>f4_layouts(
                     s_key    = ls_key
                     restrict = if_salv_c_layout=>restrict_none  ).
    cv_layout = ls_layout-layout.
    g_layout  =  cv_layout.
  ENDMETHOD.
  METHOD get_default .
    DATA: ls_layout TYPE salv_s_layout_info,
          ls_key    TYPE salv_s_layout_key.
    ls_key-report = sy-repid.
    ls_layout = cl_salv_layout_service=>get_default_layout(
                      s_key    = ls_key
                      restrict = if_salv_c_layout=>restrict_none  ).
    cv_layout = ls_layout-layout.
  ENDMETHOD .
ENDCLASS.               "VARIANT
************************************SEL CLASS FOR SELECTING FIELDS*********************************
CLASS cl_sel DEFINITION .
  PUBLIC SECTION .
    TYPES : t_vbeln  TYPE RANGE OF vbeln .
    DATA : s_vbeln TYPE t_vbeln .
    DATA : s_werks TYPE werks_ext  .
    METHODS : check_plant IMPORTING lp_werks TYPE werks_ext .
ENDCLASS .
*&---------------------------------------------------------------------*
*&       CLASS (IMPLEMENTATION)  SEL
*&---------------------------------------------------------------------*
*        TEXT
*----------------------------------------------------------------------*
CLASS cl_sel IMPLEMENTATION.
  METHOD check_plant .
    DATA : lv_werks TYPE t001w .
    IF lp_werks IS NOT INITIAL .
      SELECT SINGLE werks FROM t001w INTO lv_werks
      WHERE  werks = lp_werks.
      IF sy-subrc NE 0.
        MESSAGE 'Please enter a valid plant' TYPE 'E'.
      ENDIF.
    ENDIF .
  ENDMETHOD.
ENDCLASS.               "SEL
 
****************************FETCH CLASS FOR DATA FETCH******************************
CLASS cl_fetch DEFINITION  .
  PUBLIC SECTION .
    DATA : sel_obj TYPE REF TO cl_sel .
    DATA : it_vbap TYPE STANDARD TABLE OF vbap .
    METHODS : constructor IMPORTING ref_sel TYPE REF TO cl_sel .
    METHODS : fetch_data .
ENDCLASS .
*&---------------------------------------------------------------------*
*&       CLASS (IMPLEMENTATION)  FETCH
*&---------------------------------------------------------------------*
*        TEXT
*----------------------------------------------------------------------*
CLASS cl_fetch IMPLEMENTATION.
  METHOD constructor.
    me->sel_obj = ref_sel .
  ENDMETHOD .
  METHOD fetch_data .
    SELECT * FROM vbap INTO TABLE me->it_vbap
    UP TO 10 ROWS WHERE vbeln IN me->sel_obj->s_vbeln
    AND werks EQ me->sel_obj->s_werks .
  ENDMETHOD .
ENDCLASS.               "FETCH
 
*******************************DISPLAY DATA ******************************
CLASS cl_alv DEFINITION .
  PUBLIC SECTION .
    DATA : fetch_obj  TYPE REF TO cl_fetch .
    DATA : variant_obj TYPE REF TO cl_variant .
 
    DATA : o_alv TYPE REF TO cl_salv_table.
    METHODS : constructor IMPORTING ref_fetch TYPE REF TO cl_fetch
                                    ref_var   TYPE REF TO cl_variant.
    METHODS : get_object .
    METHODS : layout_dis .
    METHODS : display_alv .
 
ENDCLASS .
*&---------------------------------------------------------------------*
*&       Class (Implementation)  CL_ALV
*&---------------------------------------------------------------------*
*        Text
*----------------------------------------------------------------------*
CLASS cl_alv IMPLEMENTATION.
  METHOD constructor .
    me->fetch_obj   = ref_fetch .
    me->variant_obj = ref_var.
  ENDMETHOD .
  METHOD get_object .
    DATA: lx_msg TYPE REF TO cx_salv_msg.
    TRY.
        cl_salv_table=>factory(
          IMPORTING
            r_salv_table = me->o_alv
          CHANGING
            t_table      = me->fetch_obj->it_vbap ).
      CATCH cx_salv_msg INTO lx_msg.
    ENDTRY.
  ENDMETHOD .
  METHOD layout_dis.
    DATA : ls_key    TYPE salv_s_layout_key,
           lo_layout TYPE REF TO cl_salv_layout.
    DATA: lo_functions TYPE REF TO cl_salv_functions_list.
    DATA: lo_display TYPE REF TO cl_salv_display_settings.
    ls_key-report = sy-repid .
*  GET DEFAULT TOOLBAR ICONS
    lo_functions = me->o_alv->get_functions( ).
    lo_functions->set_default( abap_true ).
* GET LAYOUT OBUJECT
    lo_layout = me->o_alv->get_layout( ).
* ALLOW SAVING LAYOUT
    lo_layout->set_save_restriction( if_salv_c_layout=>restrict_none ).
    lo_layout->set_key( ls_key ).
* ALLOW DEFAULT LAYOUT CHECK BOX
    lo_layout->set_default( abap_true ).
* SETTING the layout from my class CL_VARIANT
    IF me->variant_obj->g_layout IS NOT INITIAL .
      lo_layout->set_initial_layout( me->variant_obj->g_layout  ) .
    ENDIF .
*  display zbera pattern
    lo_display = me->o_alv->get_display_settings( ).
    lo_display->set_striped_pattern( 'X' ).
  ENDMETHOD .
  METHOD display_alv .
    CALL METHOD me->get_object( ) .
    CALL METHOD me->layout_dis( ) .
    me->o_alv->display( ).
  ENDMETHOD.
ENDCLASS.               "CL_ALV
 
DATA: o_sel     TYPE REF TO cl_sel,
      o_fetch   TYPE REF TO cl_fetch,
      o_var     TYPE REF TO cl_variant,
      o_display TYPE REF TO cl_alv.
 
INITIALIZATION .
  CREATE OBJECT: o_sel,
                o_var,
                o_fetch EXPORTING ref_sel = o_sel  ,
                o_display EXPORTING ref_fetch = o_fetch  ref_var = o_var .
  cl_variant=>get_default( CHANGING cv_layout = p_vari ).
 
AT SELECTION-SCREEN .
  o_sel->check_plant( p_werks ).
 
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_vari.
  o_var->f4_variant( CHANGING cv_layout = p_vari ).
 
START-OF-SELECTION .
  o_sel->s_werks = p_werks .
  o_sel->s_vbeln = s_vbeln1[] .
  o_fetch->fetch_data( ).
 
END-OF-SELECTION .
  o_display->display_alv( ).

Final Results :

i. /PP is the default layout in our system. So, GET_DEFAULT method is working as expected.

ii. Here we have the Layout and Filter icons.

iii. Now let’s see our F4 help is working or not?

iv. /MM is user specific layout and its working fine. We have only four fields in this layout. Look at below output, our code is showing only four columns. Isn’t MVC cool?

Despite everything, do you think this report is finished and our client will get satisfied? …. An enormous NO… They will demand the Specific Fields (columns) now and yes some additional data from different tables. They will raise a change request for it and you cannot oppose it. Let’s say they want sold-to-party and ship-to-party in this report ….Oops!

So let’s move on to the next Part to modify our MODEL i.e. our Business Logic. In OOPs ABAP, if we get more changes after the developments are LIVE, we would see in next part, how easily we can handle it without much disruption.