avadaneidanut / sapphp
SAP Remote Function Modules Calls made easy using sapnwrfc.
Requires
- php: >=5.5.9
- ext-sapnwrfc: *
- illuminate/support: 5.2.*
- psy/psysh: ^0.7.2
- sabre/xml: ^1.4
This package is not auto-updated.
Last update: 2024-11-09 19:51:15 UTC
README
SAP Remote Function Modules Calls made easy using sapnwrfc and PHP.
Legal notice
SAP and other SAP products and services mentioned herein are trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other countries.
Summary
Welcome to SapPhp package. This packages is not a connector, it uses php-sapnwrfc extension to handle client - server communication. This package is intended to provide a clean object oriented interface to handle extensive data extraction using RFC calls. My development plan is to extend this class with PHP Interfaces to SAP FMs (check RfcReadTable interface)
This is an early version and I expect you to raise issues and bugs and maybe give me some suggestions.
Install
Make sure you have the php-sapnwrfc extension installed.
composer require avdaneidanut/sapphp
SAP Systems details
The package uses two methods for retrievieng SAP Systems details (ashost, sysnr, description and name) by parsing files using the \SapPhp\Repository class.
-
Parsing saplogon.ini file from:
C:/Users/{currentUser}/AppData/Roaming/SAP/Common/
. -
Parsing sapphp.xml from package root folder.
If the first method fails or returns no result the second method will be performed.
Connecting to SAP
<?php use SapPhp\Connection; use SapPhp\Exceptions\BoxNotFoundException; try { $connection = new Connection( 'box', // SAP Box Name 'user', // SAP Username 'passwd', // SAP Password '500' // SAP Client Code ); } catch(sapnwrfcConnectionException $ex) { // Do something if login failed. } catch(BoxNotFoundException $ex) { // Do something if box doesn't exist. }
Perform Function Module call
Let's get details about an user:
<?php // ... connection // Instantiate new Function Module interface. $function = $connection->fm( 'BAPI_USER_GET_DETAIL', // RFC Enable FM true // Parse result (trim all strings and decode GUIDs) ); // Get function description. print_r($function->description()); // Add import parameter. // Will trigger an \SapPhp\Exceptions\ParamNotFoundException if param is not found in function description. $function->param('USERNAME', 'USER'); // Perform function call and retrieve result. $result = $function->invoke();
How about getting details about an user using RFC_READ_TABLE
FM? Let's go:
<?php // ... connection $function = $connection->fm('RFC_READ_TABLE'); $function->param('QUERY_TABLE', 'USR01') ->param('OPTIONS', [ ['TEXT' => 'BNAME = \'USER\' OR BNAME = \'USER2\' OR BNAME LIKE \'USER5*\''] ]) ->param('ROWCOUNT', 5) ->param('DELIMITER', '~') ; $result = $function->invoke();
Very nice, we can query a table using a SQL statement. The result from this FM is dirty, fix it with explodes and array_merge, right?
[
"DATA" => [
[
"WA" => "500~USER2 ~ ~ ~ ~H~K~1~ ~ ~ ~ ~ ~ ~ ~ ~ ~0",
],
[
"WA" => "500~USER5 ~ ~ ~ ~H~K~1~ ~ ~ ~ ~ ~ ~ ~ ~ ~0",
],
[
"WA" => "500~USER55 ~ ~ ~ ~H~K~1~ ~ ~ ~ ~ ~ ~ ~ ~ ~0",
],
],
"FIELDS" => [
[
"FIELDNAME" => "MANDT",
"OFFSET" => "000000",
"LENGTH" => "000003",
"TYPE" => "C",
"FIELDTEXT" => "Client",
],
[
"FIELDNAME" => "BNAME",
"OFFSET" => "000004",
"LENGTH" => "000012",
"TYPE" => "C",
"FIELDTEXT" => "User Name in User Master Record",
],
[
"FIELDNAME" => "STCOD",
"OFFSET" => "000017",
"LENGTH" => "000020",
"TYPE" => "C",
"FIELDTEXT" => "Start menu (old, replaced by XUSTART)",
],
[
"FIELDNAME" => "SPLD",
"OFFSET" => "000038",
"LENGTH" => "000004",
"TYPE" => "C",
"FIELDTEXT" => "Spool: Output device",
],
[
"FIELDNAME" => "SPLG",
"OFFSET" => "000043",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Print parameter 1",
],
[
"FIELDNAME" => "SPDB",
"OFFSET" => "000045",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Print parameter 2",
],
[
"FIELDNAME" => "SPDA",
"OFFSET" => "000047",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Print parameter 3",
],
[
"FIELDNAME" => "DATFM",
"OFFSET" => "000049",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Date format",
],
[
"FIELDNAME" => "DCPFM",
"OFFSET" => "000051",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Decimal notation",
],
[
"FIELDNAME" => "HDEST",
"OFFSET" => "000053",
"LENGTH" => "000008",
"TYPE" => "C",
"FIELDTEXT" => "Host destination",
],
[
"FIELDNAME" => "HMAND",
"OFFSET" => "000062",
"LENGTH" => "000003",
"TYPE" => "C",
"FIELDTEXT" => "Default host client",
],
[
"FIELDNAME" => "HNAME",
"OFFSET" => "000066",
"LENGTH" => "000012",
"TYPE" => "C",
"FIELDTEXT" => "Default host user name",
],
[
"FIELDNAME" => "MENON",
"OFFSET" => "000079",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Automatic Start",
],
[
"FIELDNAME" => "MENUE",
"OFFSET" => "000081",
"LENGTH" => "000020",
"TYPE" => "C",
"FIELDTEXT" => "Menu name",
],
[
"FIELDNAME" => "STRTT",
"OFFSET" => "000102",
"LENGTH" => "000020",
"TYPE" => "C",
"FIELDTEXT" => "Start menu (old, replaced by XUSTART)",
],
[
"FIELDNAME" => "LANGU",
"OFFSET" => "000123",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Language",
],
[
"FIELDNAME" => "CATTKENNZ",
"OFFSET" => "000125",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "CATT: Test status",
],
[
"FIELDNAME" => "TIMEFM",
"OFFSET" => "000127",
"LENGTH" => "000001",
"TYPE" => "C",
"FIELDTEXT" => "Time Format (12-/24-Hour Specification)",
],
],
"OPTIONS" => [
[
"TEXT" => "TEXT' => 'BNAME = 'USER' OR BNAME = 'USER2' OR BNAME LIKE 'USER5*'",
],
],
]
But wait, how about using a FunctionModule interface that has a query builder and parses the result?
<?php // ... connection // fm method will check if RfcReadTable is an FunctionModule interface Class, if so will return a new instance. $function = $connection->fm('RfcReadTable'); // Let's do the same thing as before. $result = $function->table('usr01') // set the query table ->where('bname', ['USER', 'USER5']) // add multiple where clause (simulating where in ) ->orWhere('bname', 'LIKE', 'USER5*') // add custom comparation operator ->limit(5) // limit the result to 5 rows ->get() // perform function call, parse the result and return a \Illuminate\Support\Collection object. ; print_r($result->toArray());
And the result:
[
[
"MANDT" => "500",
"BNAME" => "USER2",
"STCOD" => "",
"SPLD" => "",
"SPLG" => "",
"SPDB" => "H",
"SPDA" => "K",
"DATFM" => "1",
"DCPFM" => "",
"HDEST" => "",
"HMAND" => "",
"HNAME" => "",
"MENON" => "",
"MENUE" => "",
"STRTT" => "",
"LANGU" => "",
"CATTKENNZ" => "",
"TIMEFM" => "0",
],
[
"MANDT" => "500",
"BNAME" => "USER5",
"STCOD" => "",
"SPLD" => "",
"SPLG" => "",
"SPDB" => "H",
"SPDA" => "K",
"DATFM" => "1",
"DCPFM" => "",
"HDEST" => "",
"HMAND" => "",
"HNAME" => "",
"MENON" => "",
"MENUE" => "",
"STRTT" => "",
"LANGU" => "",
"CATTKENNZ" => "",
"TIMEFM" => "0",
],
[
"MANDT" => "500",
"BNAME" => "USER55",
"STCOD" => "",
"SPLD" => "",
"SPLG" => "",
"SPDB" => "H",
"SPDA" => "K",
"DATFM" => "1",
"DCPFM" => "",
"HDEST" => "",
"HMAND" => "",
"HNAME" => "",
"MENON" => "",
"MENUE" => "",
"STRTT" => "",
"LANGU" => "",
"CATTKENNZ" => "",
"TIMEFM" => "0",
],
]
Take a look at RfcReadTable and QueryBuilder methods.
QueryBuilder usage.
<?php $query->where('column', 'value') // Add WHERE clause ->andWhere('column2,' 'value2') // AND logical operarator ->orWhere('column3', '<>', 'value3') // OR logical operator ->orWhere(function ($query) { // WHERE group $query->where('column11', 'value11') ->andWhere('column22', 'value22'); }) ->orWhere('column5', '<>', [1, 2, 3, 4]); // Simulate WHERE IN clause
The previous code will generate the folowing SQL query:
WHERE COLUMN = 'value' AND COLUMN2 = 'value2' OR COLUMN3 <> 'value3' OR ( COLUMN11 = 'value11' AND COLUMN22 = 'value22' ) OR ( COLUMN5 <> '1' OR COLUMN5 <> '2' OR COLUMN5 <> '3' OR COLUMN5 <> '4' )
To-do
- Aggregate multiple table results in one Collection and share the same query over multiple tables.
<?php // ... connection & function $rfcReadTable->table(['table1', 'table2', 'table3'], function($agregatter) { $aggregate->table('table1') ->with('table2') ->on('column') ->as('aggregated_table'); $aggregate->table('aggregated_table', 'table3') ->on('column2'); })->where('column', 'value');
- Add mode FunctionModule interfaces as RfcReadTable - Please send suggestions!
Support
I will help you ASAP if you find any issues in using this package.