Skip to Content
Welcome back to the “Tasting the mix of PHP and SAP” weblog series. This time, we’re going to develop an SM30 Simulator, which is the next logical step after having developed and Tasting the mix of PHP and SAP.

Before we start, I have two things to say:

Very special thanks to <B>Rich Heilman</B> and <B>John Astill</B>

    1. Remember that this app is just for testing purposes, don’t implement this on a production system…unless you want to get fired.

      Ok, now we can start. You may remember, in the firt volume of the series, I used RFC_READ_TABLE RFC in order to read the FIELDS and DATA from any table. It works fine, however I have two problems with it. You don’t know which fields are primary keys and of course it’s not released for customer use (see SAP Note 382318). Both of these are bad; for an SM30 the fact that I can’t find the primary key is particularly bad. So, my first task was to modify the FM, by creating my own version in the “customer namespace” thus I also avoid using the one from SAP that could be changed, removed or what not at anytime. Here’s the code:

      ZRFC_READ_TABLE


FUNCTION ZRFC_READ_TABLE .
*”—-


“Interfase local
*”  IMPORTING
*”     VALUE(QUERY_TABLE) LIKE  DD02L-TABNAME
*”     VALUE(DELIMITER) LIKE  SONV-FLAG DEFAULT SPACE
*”     VALUE(NO_DATA) LIKE  SONV-FLAG DEFAULT SPACE
*”     VALUE(ROWSKIPS) LIKE  SOID-ACCNT DEFAULT 0
*”     VALUE(ROWCOUNT) LIKE  SOID-ACCNT DEFAULT 0
*”  TABLES
*”      OPTIONS STRUCTURE  RFC_DB_OPT
*”      FIELDS STRUCTURE  RFC_DB_FLD
*”      DATA STRUCTURE  TAB512
*”      KEYS STRUCTURE  DD03P
*”  EXCEPTIONS
*”      TABLE_NOT_AVAILABLE
*”      TABLE_WITHOUT_DATA
*”      OPTION_NOT_VALID
*”      FIELD_NOT_VALID
*”      NOT_AUTHORIZED
*”      DATA_BUFFER_EXCEEDED
*”—-



  CALL FUNCTION ‘VIEW_AUTHORITY_CHECK’
    EXPORTING
      VIEW_ACTION                    = ‘S’
      VIEW_NAME                      = QUERY_TABLE
    EXCEPTIONS
      NO_AUTHORITY                   = 2
      NO_CLIENTINDEPENDENT_AUTHORITY = 2
      NO_LINEDEPENDENT_AUTHORITY     = 2
      OTHERS                         = 1.


  IF SY-SUBRC = 2.
    RAISE NOT_AUTHORIZED.
  ELSEIF SY-SUBRC = 1.
    RAISE TABLE_NOT_AVAILABLE.
  ENDIF.


  1. ———————————————————————-
  2. find out about the structure of QUERY_TABLE
  3. ———————————————————————-

  DATA BEGIN OF TABLE_STRUCTURE OCCURS 10.
          INCLUDE STRUCTURE DFIES.
  DATA END OF TABLE_STRUCTURE.
  “DATA TABLE_HEADER LIKE X030L.
  DATA TABLE_TYPE TYPE DD02V-TABCLASS.


  CALL FUNCTION ‘DDIF_FIELDINFO_GET’
    EXPORTING
      TABNAME              = QUERY_TABLE

  1.   FIELDNAME            = ‘ ‘
  2.   LANGU                = SY-LANGU
  3.   LFIELDNAME           = ‘ ‘
  4.   ALL_TYPES            = ‘ ‘
  5.   GROUP_NAMES          = ‘ ‘

    IMPORTING

  1.   X030L_WA             =

      DDOBJTYPE            = TABLE_TYPE

  1.   DFIES_WA             =
  2.   LINES_DESCR          =

    TABLES
      DFIES_TAB            = TABLE_STRUCTURE

  1.   FIXED_VALUES         =

    EXCEPTIONS
      NOT_FOUND            = 1
      INTERNAL_ERROR       = 2
      OTHERS               = 3
            .
  IF SY-SUBRC <> 0.
    RAISE TABLE_NOT_AVAILABLE.
  ENDIF.
  IF TABLE_TYPE = ‘INTTAB’.
    RAISE TABLE_WITHOUT_DATA.
  ENDIF.


  1. ———————————————————————-
  2. isolate first field of DATA as output field
  3. (i.e. allow for changes to structure DATA!)
  4. ———————————————————————-

  DATA LINE_LENGTH TYPE I.
  FIELD-SYMBOLS LENGTH LINE_LENGTH IN CHARACTER MODE.


  1. ———————————————————————-
  2. if FIELDS are not specified, read all available fields
  3. ———————————————————————-

  DATA NUMBER_OF_FIELDS TYPE I.
  DESCRIBE TABLE FIELDS LINES NUMBER_OF_FIELDS.
  IF NUMBER_OF_FIELDS = 0.
    LOOP AT TABLE_STRUCTURE.
      MOVE TABLE_STRUCTURE-FIELDNAME TO FIELDS-FIELDNAME.
      APPEND FIELDS.
    ENDLOOP.
  ENDIF.


  1. ———————————————————————-
  2. for each field which has to be read, copy structure information
  3. into tables FIELDS_INT (internal use) and FIELDS (output)
  4. ———————————————————————-

  DATA: BEGIN OF FIELDS_INT OCCURS 10,
          FIELDNAME  LIKE TABLE_STRUCTURE-FIELDNAME,
          TYPE       LIKE TABLE_STRUCTURE-INTTYPE,
          DECIMALS   LIKE TABLE_STRUCTURE-DECIMALS,
          LENGTH_SRC LIKE TABLE_STRUCTURE-INTLEN,
          LENGTH_DST LIKE TABLE_STRUCTURE-LENG,
          OFFSET_SRC LIKE TABLE_STRUCTURE-OFFSET,
          OFFSET_DST LIKE TABLE_STRUCTURE-OFFSET,
        END OF FIELDS_INT,
        LINE_CURSOR TYPE I.


  LINE_CURSOR = 0.

  1. for each field which has to be read …

  LOOP AT FIELDS.


    READ TABLE TABLE_STRUCTURE WITH KEY FIELDNAME = FIELDS-FIELDNAME.
    IF SY-SUBRC NE 0.
      RAISE FIELD_NOT_VALID.
    ENDIF.


  1. compute the place for field contents in DATA rows:
  2. if not first field in row, allow space for delimiter

    IF LINE_CURSOR <> 0.
      IF NO_DATA EQ SPACE AND DELIMITER NE SPACE.
        MOVE DELIMITER TO DATA+LINE_CURSOR.
      ENDIF.
      LINE_CURSOR = LINE_CURSOR + STRLEN( DELIMITER ).
    ENDIF.


  1. … copy structure information into tables FIELDS_INT
  2. (which is used internally during SELECT) …

    FIELDS_INT-FIELDNAME  = TABLE_STRUCTURE-FIELDNAME.
    FIELDS_INT-LENGTH_SRC = TABLE_STRUCTURE-INTLEN.
    FIELDS_INT-LENGTH_DST = TABLE_STRUCTURE-LENG.
    FIELDS_INT-OFFSET_SRC = TABLE_STRUCTURE-OFFSET.
    FIELDS_INT-OFFSET_DST = LINE_CURSOR.
    FIELDS_INT-TYPE       = TABLE_STRUCTURE-INTTYPE.
    FIELDS_INT-DECIMALS   = TABLE_STRUCTURE-DECIMALS.

  1. compute the place for contents of next field in DATA rows

    LINE_CURSOR = LINE_CURSOR + TABLE_STRUCTURE-LENG.
    IF LINE_CURSOR > LINE_LENGTH AND NO_DATA EQ SPACE.
      RAISE DATA_BUFFER_EXCEEDED.
    ENDIF.
    APPEND FIELDS_INT.


  1. … and into table FIELDS (which is output to the caller)

    FIELDS-FIELDTEXT = TABLE_STRUCTURE-FIELDTEXT.
    FIELDS-TYPE      = TABLE_STRUCTURE-INTTYPE.
    FIELDS-LENGTH    = FIELDS_INT-LENGTH_DST.
    FIELDS-OFFSET    = FIELDS_INT-OFFSET_DST.
    MODIFY FIELDS.


  ENDLOOP.

  1. end of loop at FIELDS


  1. ———————————————————————-
  2. read data from the database and copy relevant portions into DATA
  3. ———————————————————————-
  4. output data only if NO_DATA equals space (otherwise the structure
  5. information in FIELDS is the only result of the module)

  IF NO_DATA EQ SPACE.


    DATA: BEGIN OF WORK, BUFFER(30000), END OF WORK.


    FIELD-SYMBOLS: WHERE (OPTIONS).


      IF SY-DBCNT GT ROWSKIPS.


  1.   copy all relevant fields into DATA (output) table

        LOOP AT FIELDS_INT.
          IF FIELDS_INT-TYPE = ‘P’.
            ASSIGN COMPONENT FIELDS_INT-FIELDNAME
                OF STRUCTURE +FIELDS_INT-OFFSET_DST(FIELDS_INT-LENGTH_DST).
        ENDLOOP.

  1.   end of loop at FIELDS_INT

        APPEND DATA.


        IF ROWCOUNT > 0 AND SY-DBCNT GE ROWCOUNT. EXIT. ENDIF.


      ENDIF.


    ENDSELECT.


  ENDIF.


  1. ———————————————————————-
  2. Get the primary key fields
  3. ———————————————————————-

DATA: NAME TYPE DDOBJNAME.


MOVE QUERY_TABLE TO NAME.


CALL FUNCTION ‘DDIF_TABL_GET’
  EXPORTING
    NAME                = NAME

  1.   STATE               = ‘A’
  2.   LANGU               = ‘ ‘
  3. IMPORTING
  4.   GOTSTATE            =
  5.   DD02V_WA            =
  6.   DD09L_WA            =

  TABLES
    DD03P_TAB           = KEYS

  1.   DD05M_TAB           =
  2.   DD08V_TAB           =
  3.   DD12V_TAB           =
  4.   DD17V_TAB           =
  5.   DD35V_TAB           =
  6.   DD36M_TAB           =

EXCEPTIONS
   ILLEGAL_INPUT       = 1
   OTHERS              = 2.


ENDFUNCTION.

As you can see, I just add a new table named KEYS and called FM DDIF_TABL_GET. Now, we know which fields are primary keys.

Next thing we need is a custom FM that allows our application to INSERT, UPDATE or DELETE any record from ANY TABLE (be very careful here as many tables are cluster tables or otherwise complex). Sounds cool right? Yeah…it’s really cool.

You can create the ZTABLE_OPERATION, just using an 255 characters domain data.

ZRFC_TABLE_OPERATIONS_LINE


FUNCTION ZRFC_TABLE_OPERATIONS_LINE.
*”—-


“Interfase local
*”  IMPORTING
*”     VALUE(QUERY_TABLE) LIKE  DD02L-TABNAME
*”     VALUE(OPERATION) LIKE  BDLDATCOL-TYPE
*”     VALUE(FIELDS) LIKE  ZTABLE_OPERATION-FIELDS
*”     VALUE(DATA) LIKE  ZTABLE_OPERATION-DATA
*”  EXCEPTIONS
*”      RECORD_NOT_INSERTED
*”      RECORD_NOT_UPDATED
*”      RECORD_NOT_DELETED
*”      NOT_AUTHORIZED
*”      TABLE_NOT_AVAILABLE
*”—-



  CALL FUNCTION ‘VIEW_AUTHORITY_CHECK’
    EXPORTING
      VIEW_ACTION                    = ‘S’
      VIEW_NAME                      = QUERY_TABLE
    EXCEPTIONS
      NO_AUTHORITY                   = 2
      NO_CLIENTINDEPENDENT_AUTHORITY = 2
      NO_LINEDEPENDENT_AUTHORITY     = 2
      OTHERS                         = 1.


  IF SY-SUBRC = 2.
    RAISE NOT_AUTHORIZED.
  ELSEIF SY-SUBRC = 1.
    RAISE TABLE_NOT_AVAILABLE.
  ENDIF.


*=======================================================================

  1. Types.

*=======================================================================
  TYPES: X_LINES TYPE STRING.


*=======================================================================

  1. Internal Tables.

*=======================================================================
  DATA: DESCR_STRUCT_REF TYPE REF TO CL_ABAP_STRUCTDESCR,
        DATAREF TYPE REF TO DATA,
        WA_FCAT TYPE LVC_S_FCAT,
        IT_FIELDCATALOG TYPE LVC_T_FCAT,
        T_LINES TYPE STANDARD TABLE OF X_LINES,
        T_FIELDS TYPE STANDARD TABLE OF X_LINES WITH HEADER LINE,
        NEW_LINE  TYPE REF TO DATA.


  DATA: W_LINES TYPE STRING.


*=======================================================================

  1. Variables.

*=======================================================================
  DATA: W_TABIX LIKE SY-TABIX.


*=======================================================================

  1. Field-Symbols.

*=======================================================================
  FIELD-SYMBOLS:
                .


*=======================================================================

  1. Create a dynamic internal table.

*=======================================================================
  CREATE DATA DATAREF TYPE (QUERY_TABLE).


  ASSIGN DATAREF->* TO CREATE_DYNAMIC_TABLE
    EXPORTING
      IT_FIELDCATALOG           = IT_FIELDCATALOG
    IMPORTING
      EP_TABLE                  = DATAREF.

  1.    EXCEPTIONS
  2.      GENERATE_SUBPOOL_DIR_FULL = 1
  3.      OTHERS                    = 2.


  ASSIGN DATAREF->* TO .


*=======================================================================

  1. Fill the dynamic internal table.

*=======================================================================
    SPLIT DATA AT ‘/’ INTO TABLE T_LINES.
    SPLIT FIELDS AT ‘/’ INTO TABLE T_FIELDS.
    LOOP AT T_LINES ASSIGNING .


*============================== ========================================

  1. Perform task depending of the choose operation.

*=======================================================================
    CASE OPERATION.
      WHEN ‘I’.
        MODIFY (QUERY_TABLE) FROM TABLE

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Enrico Karg
    Hello,

    I am a PHP developer with no ABAP Skills:-(
    I used the normal RFC_Read_Table like you had shown in the blog before. Now I saw this and I want to use it as well. But there are several problems with the ABAP part in this example.
    What should I insert in the import/export and maybe table fiels? I think this is the source for the errors I get when I try to check the Fm in my MiniSAP system.

    (0) 
    1. Alvaro Tejada Galindo Post author
      Hi Enrico:

      The only difference between normal RFC_READ_TABLE and my custom FM is that I had included a KEYS table…Which is only used to get the key fields of the table…Everything else is exactly the same -:) You don’t need to fill TABLE parameters for this one -:) Just QUERY_TABLE and DELIMTER (Which should be “/”).

      Talking about ZRFC_TABLE_OPERATIONS_LINE, which doesn’t exist on MiniSAP, you need to pass the Query_Table (as RFC_READ_TABLE), OPERATION (U=Update,I=Insert,D=Delete), FIELDS and DATA, which are a long string containing the FIELDS of the table and the DATA to manipulate separated by an “/” symbol.

      If you got more question, you can post in the forum https://forums.sdn.sap.com/forum.jspa?forumID=124
      or write to my personal mail which you can find on my business card.

      P.S: Thanx for being interested in the PHP/SAP integration -;)

      Greetings,

      Blag.

      (0) 

Leave a Reply