Nesse documento tem como objetivo explicar, de forma simples e objetiva, como realizar de forma simples uma conexão usando RFCs/Webservices (WSDL) com uma aplicação PHP, utilizando a classe SoapClient. A motivação para criar esse documento em português vem da falta de artigos desse tipo na nossa língua.
O documento será dividido em duas partes:
Iremos utilizar como exemplo uma situação em que uma aplicação PHP tem as seguintes necessidades de integração com o SAP:
Para realizar essa tarefa, vamos dividir nosso exemplo em três partes, sendo cada uma a resolução de cada uma das nossas três necessidades. Algumas
Para isso, vamos criar um webservice baseado em uma RFC já pronta, a função BAPI_USER_GET_DETAIL.
Figura 1: Caminho para criação de Web Service
Figura 2: Criando Web Service - Tela 1 (nome e descrição do Web Service)
Figura 3: Criando Web Service - Tela 2 (opção para mapear o nome da função p/ gerar a operação)
Figura 4: Criando Web Service - Tela 3 (menos seguro, para simplificar nosso exemplo)
Figura 5: Criando Web Service - Tela 4 (meu pacote local $SDN)
Figura 6: Criando Web Service - Tela 5 (confirmação)
Após esses 5 telas, o Web Service está basicamente criado. Irá ser aberta uma tela de definição do serviço, que deveremos somente ativar e utilizar como base no futuro para verificar os parâmetros de entrada e saída.
Figura 7: Criando Web Service - Tela 6 (Definição do Serviço)
Nesse momento, para finalizar só precisamos pegar a URL do nosso WSDL, para utilizarmos nas nossas classes PHP. Para isso, iremos acessar os detalhes do Web Service na transação SOAMANAGER (necessita que o básico de Webdynpro esteja configurado no ambiente) e entrar nas configurações simplificadas, onde é conseguiremos acessar a URl de maneira bem simples:
Figura 8: SOAMANAGER - Tela 1
Figura 9: SOAMANAGER - Tela 2 (Não esquecer de marcar o checkbox 'User Name/Password (Basic)' e salvar, para gerar uma configuração válida)
Nesse momento, para finalizamos a tarefa 1! Vamos para a próxima tarefa.
Para essa tarefa, vamos optar por desenvolver nosso próprio módulo de função e criar nossos Web Service.
Código-fonte do módulo de função:
FUNCTION zrw_user_copy.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" VALUE(USER_REFERENCE) LIKE USR02-BNAME
*" VALUE(NEW_USER) LIKE USR02-BNAME
*" VALUE(PASSWORD) TYPE SUID_ST_NODE_PASSWORD-PASSWORD OPTIONAL
*" VALUE(WITH_ADDRESS) TYPE CHAR01 DEFAULT 'X'
*" VALUE(WITH_PARAMETERS) TYPE CHAR01 DEFAULT 'X'
*" VALUE(WITH_REFUSER) TYPE CHAR01 DEFAULT 'X'
*" VALUE(WITH_DEFAULTS) TYPE CHAR01 DEFAULT 'X'
*" VALUE(WITH_UCLASS) TYPE CHAR01 DEFAULT 'X'
*" EXPORTING
*" VALUE(NEW_PASS) TYPE SUID_ST_NODE_PASSWORD
*" EXCEPTIONS
*" INTERNAL_ERROR
*"----------------------------------------------------------------------
DATA: lv_new_user TYPE suid_st_node_root,
ls_password TYPE suid_st_node_password.
TRY.
CALL METHOD cl_identity=>copy
EXPORTING
iv_id_source = user_reference
iv_id_destination = new_user
iv_copy_address = with_address
iv_copy_defaults = with_defaults
iv_copy_parameters = with_parameters
iv_copy_refuser = with_refuser
iv_copy_roles = abap_true
iv_copy_profiles = abap_true
iv_copy_groups = abap_true
iv_copy_personalization = abap_true
iv_copy_uclass = with_uclass
iv_copy_easy_access = abap_true
IMPORTING
ev_node_root_destination = lv_new_user.
IF lv_new_user-idref IS INITIAL.
RAISE internal_error.
ENDIF.
IF password IS INITIAL.
CALL METHOD lv_new_user-idref->if_identity_password~password_generate
EXPORTING
iv_return_pwd_only = space
iv_downward_comp = abap_true
IMPORTING
ev_generated_password = new_pass.
ELSE.
ls_password-password = password.
lv_new_user-idref->if_identity_password~set_password( ls_password ).
ENDIF.
lv_new_user-idref->if_identity_password~set_password_to_initial( ).
cl_identity=>do_save( ).
COMMIT WORK.
CATCH cx_suid_identity .
RAISE internal_error.
ENDTRY.
ENDFUNCTION.
Essa função utiliza como base a classe CL_IDENTITY para realizar as operações de cópia e geração de senha. Não vou entrar em detalhes mas caso tenham dúvidas sobre o funcionamento da função, fiquem a vontade nos comentários. Repitam o procedimento de criação do Web Service da tarefa 1 e anotem a URL do WSDL.
Vamos utilizar a mesma base da tarefa anterior, porém acessando alguns métodos diferentes:
FUNCTION zrw_user_reset_password.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(IV_USER) TYPE USR02-BNAME
*" REFERENCE(IV_NEW_PASSWORD) TYPE SUID_ST_NODE_PASSWORD-PASSWORD
*" OPTIONAL
*" EXPORTING
*" REFERENCE(EV_PASSWORD) TYPE SUID_ST_NODE_PASSWORD-PASSWORD
*" EXCEPTIONS
*" INVALID_USER
*"----------------------------------------------------------------------
DATA: lo_user TYPE REF TO cl_identity,
lt_users TYPE suid_tt_node_root,
lt_bnames TYPE suid_tt_bname,
ls_user LIKE LINE OF lt_users,
ls_bname LIKE LINE OF lt_bnames,
ls_password TYPE suid_st_node_password,
lv_locked TYPE boolean.
TRY.
ls_bname-bname = iv_user.
APPEND ls_bname TO lt_bnames.
CALL METHOD cl_identity=>retrieve_for_update
EXPORTING
it_bname = lt_bnames
IMPORTING
et_node_root = lt_users.
READ TABLE lt_users INTO ls_user INDEX 1.
IF sy-subrc IS NOT INITIAL.
RAISE invalid_user.
ENDIF.
IF iv_new_password IS INITIAL.
CALL METHOD ls_user-idref->if_identity_password~password_generate
EXPORTING
iv_return_pwd_only = space
iv_downward_comp = abap_true
IMPORTING
ev_generated_password = ls_password.
ev_password = ls_password-password.
ELSE.
ev_password = ls_password-password = iv_new_password.
ls_user-idref->if_identity_password~set_password( ls_password ).
ENDIF.
CALL METHOD ls_user-idref->get_lockstatus
IMPORTING
ev_locked_by_failed_logon = lv_locked.
IF lv_locked EQ abap_true.
ls_user-idref->action_unlock( ).
ENDIF.
ls_user-idref->if_identity_password~set_password_to_initial( ).
cl_identity=>do_save( ).
COMMIT WORK.
CATCH cx_suid_identity .
ENDTRY.
ENDFUNCTION.
Novamente não vou entrar em detalhes mas caso tenham dúvidas sobre o funcionamento da função, fiquem a vontade nos comentários. Repitam o procedimento de criação do Web Service da tarefa 1 e anotem a URL do WSDL.
No nosso exemplo vamos usar como mdelo uma classe que iremos concentrar todos os webservices e um arquivo consumidor que irá instanciar um objeto dessa classe e utilizar as operações
Classe dos Webservices:
<?php
/**
*
* @author Renan
*
*/
class SAPWebServices {
const SERVER = 'http://localhost:8000';
//WSDL paths
const ZRW_WS_GET_USER_DETAIL = '/sap/bc/srt/wsdl/bndg_005056C000081ED39DC1E10DA9C97287/soap11/wsdl11/allinone/standard/document?sap-client=800';
const ZRW_WS_RESET_PASS = '/sap/bc/srt/wsdl/bndg_005056C000081ED39DCE159B661ABBB1/soap11/wsdl11/allinone/standard/document?sap-client=800';
const ZRW_WS_COPY_USER = '/sap/bc/srt/wsdl/bndg_005056C000081ED39DDE16E7906E7BB1/soap11/wsdl11/allinone/standard/document?sap-client=800';
//default values
const INITIAL_PASS = 'inicial123';
const ABAP_TRUE = 'X';
const ABAP_FALSE = '';
/**
*
* @var array SAP Logon Details
*/
private $SOAP_OPTS;
/**
*
* @var SoapClient Soap Object
*/
private $client;
function __construct() {
$this->SOAP_OPTS = array (
'login' => 'RENAN',
'password' => 'mypassword',
'features' => SOAP_SINGLE_ELEMENT_ARRAYS
);
}
/**
* Call websevice ZRW_WS_GET_USER_DETAIL (BAPI_USER_GET_DETAIL)
*
* @param string $user_name
*
*/
public function get_user_detail($user_name) {
$this->client = new SoapClient ( SAPWebServices::SERVER . SAPWebServices::ZWEB_USER_DETAIL, $this->SOAP_OPTS );
$params = array (
'Username' => "$user_name",
'Return' => ''
);
try {
return $this->client->UserGetDetail ( $params );
} catch ( SoapFault $e ) {
throw $e;
}
}
/**
* Call websevice ZRW_WS_RESET_PASS
*
* @param string $user_name
* @param string $initial_password
*/
public function reset_password($user_name, $initial_password = NULL) {
$this->client = new SoapClient ( SAPWebServices::SERVER . SAPWebServices::ZRW_WS_RESET_PASS, $this->SOAP_OPTS );
$params = array (
'Username' => $user_name,
'NewPassword' => $initial_password,
'EvPassword' => '',
);
try {
return $this->client->ResetPassword ( $params );
} catch ( SoapFault $e ) {
throw $e;
}
}
/**
* Call websevice ZRW_WS_COPY_USER
*
* @param string $user_name
* @param string $user_reference
*/
public function clone_user($user, $user_reference, $initial_password = null) {
$this->client = new SoapClient ( SAPWebServices::SERVER . SAPWebServices::ZRW_WS_COPY_USER, $this->SOAP_OPTS );
$params = array (
'UserReference' => $user_reference,
'NewUser' => $user,
'Password' => $initial_password,
'NewPass' => array('Password' => ''),
'WithAddress' => SAPWebServices::ABAP_FALSE,
);
try {
return $this->client->UserCopy ( $params );
} catch ( SoapFault $e ) {
throw $e;
}
}
}
?>
Arquivo que usará a classe para consumir os Web Services:
<?php
require_once 'sap/SAPWebServices.php';
try {
$sap = new SAPWebServices ();
$result = $sap->get_user_detail('RENAN');
$result = $sap->clone_user('TESTE_USER' , 'RW_TEMPLATE');
$result = $sap->reset_password('TESTE_USER');
}
catch ( SoapFault $exception ) {
print "***Caught Exception***<br />";
echo '<pre>';
print_r ( $exception );
echo '</pre>';
print "***END Exception***<br />";
die ();
}
print "***Success***<br />";
echo '<pre>';
print_r ( $result );
echo '</pre>';
?>
Pronto! Se você seguiu todos os passos, você terá o seus arquivos PHP acessandos as RFCs do SAP via WebServices/Soap de maneira fácil e rápida, sem integradores de terceiros ou classes customizadas, tudo 100% nativo.
User | Count |
---|---|
1 | |
1 | |
1 | |
1 |