From 8f738ab74b4e8759f3503bef1062c5b10a4acf3a Mon Sep 17 00:00:00 2001 From: Gregor Date: Wed, 30 Oct 2019 10:41:45 +0100 Subject: [PATCH 01/27] composer switch to dev versions for major update --- composer.json | 8 ++-- composer.lock | 105 ++++++++++++++++++++++++++------------------------ 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/composer.json b/composer.json index f249f33..1090b84 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "koucky" ], "provide": { - "php-sap/interfaces": "~1.0.0" + "php-sap/interfaces": "v2.x-dev" }, "conflict": { "php-sap/saprfc-harding": "*", @@ -32,13 +32,13 @@ "require": { "php": "~5.5.0", "ext-saprfc": "*", - "php-sap/interfaces": "^1.0", - "php-sap/common": "^2.0" + "php-sap/interfaces": "v2.x-dev", + "php-sap/common": "v3.x-dev" }, "require-dev": { "ext-json": "*", "phpunit/phpunit": "^4.8", - "php-sap/integration-tests": "^1.0" + "php-sap/integration-tests": "dev-php5" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 31e4f4f..37d4ce5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,26 +4,26 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "57dc5597b8edc85749479e59c8e04e57", + "content-hash": "244bc31803b2dc3c23c68baa9d4e7b76", "packages": [ { "name": "php-sap/common", - "version": "v2.1.0", + "version": "v3.x-dev", "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "b8c44683143fd4d122ef6928a49304b7d692f431" + "reference": "0357478f198a7ad8224bcaa6503289a0eaed3bf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/b8c44683143fd4d122ef6928a49304b7d692f431", - "reference": "b8c44683143fd4d122ef6928a49304b7d692f431", + "url": "https://api.github.com/repos/php-sap/common/zipball/0357478f198a7ad8224bcaa6503289a0eaed3bf6", + "reference": "0357478f198a7ad8224bcaa6503289a0eaed3bf6", "shasum": "" }, "require": { "ext-json": "*", "php": ">=5.5.0", - "php-sap/interfaces": "^1.0", + "php-sap/interfaces": "v2.x-dev", "psr/container": "^1.0" }, "require-dev": { @@ -56,23 +56,24 @@ "PHPSAP", "php-sap" ], - "time": "2019-01-23T11:06:58+00:00" + "time": "2019-10-29T15:51:06+00:00" }, { "name": "php-sap/interfaces", - "version": "v1.0.0", + "version": "v2.x-dev", "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "4df96cbf6eb792463641ab55611173e7e6fd2761" + "reference": "a1ebdfce972dab48410014d11d426ea850784890" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/4df96cbf6eb792463641ab55611173e7e6fd2761", - "reference": "4df96cbf6eb792463641ab55611173e7e6fd2761", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/a1ebdfce972dab48410014d11d426ea850784890", + "reference": "a1ebdfce972dab48410014d11d426ea850784890", "shasum": "" }, "require": { + "ext-json": "*", "php": ">=5.5.0" }, "conflict": { @@ -102,7 +103,7 @@ "interfaces", "php-sap" ], - "time": "2019-01-16T08:33:23+00:00" + "time": "2019-10-29T15:33:14+00:00" }, { "name": "psr/container", @@ -259,24 +260,24 @@ }, { "name": "php-sap/integration-tests", - "version": "v1.0.4", + "version": "dev-php5", "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "9b2e64148f234cf877c4f630bb4905ccc14cb602" + "reference": "884ad7a983b3f7c098811b022d243f64561a9930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/9b2e64148f234cf877c4f630bb4905ccc14cb602", - "reference": "9b2e64148f234cf877c4f630bb4905ccc14cb602", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/884ad7a983b3f7c098811b022d243f64561a9930", + "reference": "884ad7a983b3f7c098811b022d243f64561a9930", "shasum": "" }, "require": { "ext-json": "*", "kba-team/memory-container": "^1.0", "php": "^5.5", - "php-sap/common": "^2.0", - "php-sap/interfaces": "^1.0", + "php-sap/common": "v3.x-dev", + "php-sap/interfaces": "v2.x-dev", "phpunit/phpunit": "^4.8" }, "type": "library", @@ -298,7 +299,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-01-23T12:34:30+00:00" + "time": "2019-10-30T09:20:07+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -448,22 +449,22 @@ }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", + "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, @@ -478,8 +479,8 @@ } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -507,7 +508,7 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2019-10-03T11:07:50+00:00" }, { "name": "phpunit/php-code-coverage", @@ -883,6 +884,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, { @@ -1259,16 +1261,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "version": "v1.12.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", "shasum": "" }, "require": { @@ -1280,7 +1282,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.12-dev" } }, "autoload": { @@ -1297,12 +1299,12 @@ ], "authors": [ { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { - "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -1313,20 +1315,20 @@ "polyfill", "portable" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2019-08-06T08:03:45+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.21", + "version": "v3.4.32", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea" + "reference": "768f817446da74a776a31eea335540f9dcb53942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/554a59a1ccbaac238a89b19c8e551a556fd0e2ea", - "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea", + "url": "https://api.github.com/repos/symfony/yaml/zipball/768f817446da74a776a31eea335540f9dcb53942", + "reference": "768f817446da74a776a31eea335540f9dcb53942", "shasum": "" }, "require": { @@ -1372,20 +1374,20 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-01-01T13:45:19+00:00" + "time": "2019-09-10T10:38:46+00:00" }, { "name": "webmozart/assert", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", "shasum": "" }, "require": { @@ -1393,8 +1395,7 @@ "symfony/polyfill-ctype": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "extra": { @@ -1423,12 +1424,16 @@ "check", "validate" ], - "time": "2018-12-25T11:19:39+00:00" + "time": "2019-08-24T08:43:50+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "php-sap/interfaces": 20, + "php-sap/common": 20, + "php-sap/integration-tests": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 93d89e9153bf72be54a83ffa4c65cb589845e662 Mon Sep 17 00:00:00 2001 From: Gregor Date: Wed, 30 Oct 2019 17:30:27 +0100 Subject: [PATCH 02/27] adapt SapRfcFunction class to new API methods --- composer.lock | 78 ++++++-- src/AbstractRemoteFunctionCall.php | 8 +- src/SapRfcFunction.php | 274 ++++++++++++++++++----------- 3 files changed, 239 insertions(+), 121 deletions(-) diff --git a/composer.lock b/composer.lock index 37d4ce5..4ee274a 100644 --- a/composer.lock +++ b/composer.lock @@ -12,26 +12,24 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "0357478f198a7ad8224bcaa6503289a0eaed3bf6" + "reference": "f0f53674fa83d49f95402e3424dab0d863eae051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/0357478f198a7ad8224bcaa6503289a0eaed3bf6", - "reference": "0357478f198a7ad8224bcaa6503289a0eaed3bf6", + "url": "https://api.github.com/repos/php-sap/common/zipball/f0f53674fa83d49f95402e3424dab0d863eae051", + "reference": "f0f53674fa83d49f95402e3424dab0d863eae051", "shasum": "" }, "require": { "ext-json": "*", "php": ">=5.5.0", + "php-sap/datetime": "^1.1", "php-sap/interfaces": "v2.x-dev", "psr/container": "^1.0" }, "require-dev": { "phpunit/phpunit": "^4.8" }, - "suggest": { - "php-sap/datetime": "Cast and/or export SAP week date, time and timestamp formats to/from DateTime." - }, "type": "library", "autoload": { "psr-4": { @@ -56,7 +54,57 @@ "PHPSAP", "php-sap" ], - "time": "2019-10-29T15:51:06+00:00" + "time": "2019-10-30T15:37:41+00:00" + }, + { + "name": "php-sap/datetime", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-sap/datetime.git", + "reference": "caf2c0df6b6909d7d107388a501961aecee1ce43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-sap/datetime/zipball/caf2c0df6b6909d7d107388a501961aecee1ce43", + "reference": "caf2c0df6b6909d7d107388a501961aecee1ce43", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpsap\\DateTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gregor J.", + "email": "gregor-j@users.noreply.github.com", + "role": "developer" + } + ], + "description": "Extends PHP's DateTime class by SAP week, date, time and timestamp format.", + "keywords": [ + "PHPSAP", + "date", + "datetime", + "php-sap", + "sap", + "time", + "timestamp", + "week" + ], + "time": "2019-01-21T13:28:53+00:00" }, { "name": "php-sap/interfaces", @@ -64,12 +112,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "a1ebdfce972dab48410014d11d426ea850784890" + "reference": "c885680649baf9e5769842302235c6e0df8a9ba7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/a1ebdfce972dab48410014d11d426ea850784890", - "reference": "a1ebdfce972dab48410014d11d426ea850784890", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/c885680649baf9e5769842302235c6e0df8a9ba7", + "reference": "c885680649baf9e5769842302235c6e0df8a9ba7", "shasum": "" }, "require": { @@ -103,7 +151,7 @@ "interfaces", "php-sap" ], - "time": "2019-10-29T15:33:14+00:00" + "time": "2019-10-30T15:27:23+00:00" }, { "name": "psr/container", @@ -264,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "884ad7a983b3f7c098811b022d243f64561a9930" + "reference": "14dcfc3d80466a4bac0825ac716c62e63977552c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/884ad7a983b3f7c098811b022d243f64561a9930", - "reference": "884ad7a983b3f7c098811b022d243f64561a9930", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/14dcfc3d80466a4bac0825ac716c62e63977552c", + "reference": "14dcfc3d80466a4bac0825ac716c62e63977552c", "shasum": "" }, "require": { @@ -299,7 +347,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-10-30T09:20:07+00:00" + "time": "2019-10-30T16:23:49+00:00" }, { "name": "phpdocumentor/reflection-common", diff --git a/src/AbstractRemoteFunctionCall.php b/src/AbstractRemoteFunctionCall.php index 24afc65..f2255e8 100644 --- a/src/AbstractRemoteFunctionCall.php +++ b/src/AbstractRemoteFunctionCall.php @@ -11,7 +11,9 @@ namespace phpsap\saprfc; +use phpsap\interfaces\exceptions\IIncompleteConfigException; use phpsap\interfaces\IConfig; +use phpsap\interfaces\IConnection; /** * Class phpsap\saprfc\AbstractRemoteFunctionCall @@ -26,9 +28,9 @@ abstract class AbstractRemoteFunctionCall extends \phpsap\classes\AbstractRemote { /** * Create a connection instance using the given config. - * @param \phpsap\interfaces\IConfig $config - * @return \phpsap\interfaces\IConnection|\phpsap\saprfc\SapRfcConnection - * @throws \phpsap\interfaces\exceptions\IIncompleteConfigException + * @param IConfig $config + * @return IConnection|SapRfcConnection + * @throws IIncompleteConfigException */ protected function createConnectionInstance(IConfig $config) { diff --git a/src/SapRfcFunction.php b/src/SapRfcFunction.php index a45f5db..7b89f34 100644 --- a/src/SapRfcFunction.php +++ b/src/SapRfcFunction.php @@ -11,9 +11,21 @@ namespace phpsap\saprfc; +use InvalidArgumentException; +use LogicException; use phpsap\classes\AbstractFunction; +use phpsap\classes\Api\Element; +use phpsap\classes\Api\Struct; +use phpsap\classes\Api\Table; +use phpsap\classes\Api\Value; +use phpsap\classes\RemoteApi; use phpsap\exceptions\FunctionCallException; use phpsap\exceptions\UnknownFunctionException; +use phpsap\interfaces\Api\IArray; +use phpsap\interfaces\Api\IElement; +use phpsap\interfaces\Api\IValue; +use phpsap\interfaces\IApi; +use phpsap\interfaces\IFunction; /** * Class phpsap\saprfc\SapRfcFunction @@ -46,10 +58,10 @@ class SapRfcFunction extends AbstractFunction /** * Invoke the prepared function call. * @return array - * @throws \phpsap\exceptions\FunctionCallException - * @throws \LogicException + * @throws FunctionCallException + * @throws LogicException */ - protected function execute() + public function invoke() { $this->setSaprfcParameters(); $result = @saprfc_call_and_receive($this->function); @@ -82,8 +94,8 @@ public function __destruct() * All parameter names will be converted to upper case. * @param string $name * @param array|string|float|int|bool|null $value - * @return \phpsap\interfaces\IFunction $this - * @throws \InvalidArgumentException + * @return IFunction $this + * @throws InvalidArgumentException */ public function setParam($name, $value) { @@ -96,7 +108,7 @@ public function setParam($name, $value) /** * Create a remote function call resource. * @return mixed - * @throws \phpsap\exceptions\UnknownFunctionException + * @throws UnknownFunctionException */ protected function getFunction() { @@ -113,47 +125,90 @@ protected function getFunction() } /** - * Retrieve the interface of the remote function. - * @return array + * Export all function call parameters. + * @throws LogicException + * @throws FunctionCallException */ - protected function getRemoteInterface() + private function setSaprfcParameters() { - if ($this->functionInterface === null) { - $this->functionInterface = []; - foreach ($this->saprfcFunctionInterface() as $element) { - $this->importRemoteInterfaceElement($element); + foreach ($this->getApi()->getInputValues() as $input) { + $name = $input->getName(); + $value = $this->getParam($name); + if ($value === null && !$input->isOptional()) { + throw new FunctionCallException(sprintf( + 'Missing parameter \'%s\' for function call \'%s\'!', + $name, + $this->getName() + )); + } + $result = @saprfc_import($this->function, $name, $value); + if ($result !== true) { + throw new LogicException(sprintf( + 'Assigning param %s, expected type %s, actual type %s to function %s failed.', + $name, + $input->getType(), + gettype($value), + $this->getName() + )); + } + } + + foreach ($this->getApi()->getTables() as $table) { + $result = @saprfc_table_init($this->function, $table->getName()); + if ($result !== true) { + throw new LogicException(sprintf( + 'Initializing table %s for function %s failed.', + $table->getName(), + $this->getName() + )); } } - return $this->functionInterface; } /** - * Import a remote function call interface element. - * @param array $element + * Import results from the function call. + * @return array */ - private function importRemoteInterfaceElement($element) + private function getSaprfcResults() { - $name = strtoupper($element['name']); - $type = $this->remoteInterfaceType($element['type'], $element['def']); - $members = $element['def']; - $this->functionInterface[$name] = ['type' => $type, 'members' => $members]; + $result = []; + foreach ($this->getApi()->getOutputValues() as $output) { + $name = $output->getName(); + $value = @saprfc_export($this->function, $name); + $result[$name] = $output->cast(trim($value)); + unset($name, $value); + } + foreach ($this->getApi()->getTables() as $table) { + $name = $table->getName(); + $rows = []; + $max = @saprfc_table_rows($this->function, $name); + for ($index = 1; $index <= $max; $index++) { + $rows[] = @saprfc_table_read($this->function, $name, $index); + } + $result[$name] = $table->cast($rows); + unset($name, $rows, $max, $index); + } + return $result; } /** - * Get the remote interface definition type. - * @param string $type - * @param array $def - * @return string + * Extract the remote function API and return an API description class. + * @return IApi + * @throws InvalidArgumentException + * @throws LogicException */ - private function remoteInterfaceType($type, $def) + public function extractApi() { - if ($type !== 'TABLE' - && isset($def[0]['name']) - && $def[0]['name'] !== '' - ) { - return sprintf('%s_STRUCT', $type); + $api = new RemoteApi(); + foreach ($this->saprfcFunctionInterface() as $element) { + $api->add($this->createApiValue( + strtoupper($element['name']), + $this->typeToDirection($element['type']), + (bool)$element['optional'], + $element['def'] + )); } - return $type; + return $api; } /** @@ -170,97 +225,110 @@ private function saprfcFunctionInterface() } /** - * Export all function call parameters. - * @throws \LogicException + * @param string $name + * @param string $direction + * @param bool $optional + * @param array $def + * @return IValue + * @throws LogicException */ - private function setSaprfcParameters() + private function createApiValue($name, $direction, $optional, $def) { - foreach ($this->getRemoteInterface() as $name => $definition) { - $result = $this->setSapRfcParameter($name, $definition['type'], $definition['members']); - if ($result !== true) { - throw new \LogicException(sprintf( - 'Assigning param %s, type %s, value %s to function %s failed.', - $name, - $definition['type'], - gettype($this->getParam($name)), - $this->getName() - )); - } + if ($direction === IArray::DIRECTION_TABLE) { + return new Table($name, $optional, $this->createMembers($def)); + } + if ($def[0]['name'] !== '') { + return new Struct($name, $direction, $optional, $this->createMembers($def)); } + return new Value($this->abapToType($def[0]['abap']), $name, $direction, $optional); } /** - * Export a single function call parameter. - * @param string $name The remote function call parameter name. - * @param string $type The remote function call parameter type. - * @param array $members The members of a remote function call parameter. - * @return bool success? - * @throws \LogicException + * Create members from the def array. + * @param array $members + * @return array + * @throws LogicException */ - private function setSapRfcParameter($name, $type, $members) + private function createMembers($members) { - switch ($type) { - case 'IMPORT': - $param = $this->getParam($name, ''); - $result = @saprfc_import($this->function, $name, $param); + $result = []; + foreach ($members as $member) { + $result[] = new Element($this->abapToType($member['abap']), $member['name']); + } + return $result; + } + + /** + * Convert SAPRFC abap datatype to PHP-SAP datatype. + * @param string $dataType + * @return string + * @throws LogicException + */ + private function abapToType($dataType) + { + switch ($dataType) { + case 'B': //1-byte integer (internal) + //fall through + case 'S': //2-byte integer (internal) + //fall through + case 'I': //4-byte integer + //fall through + case 'INT8': //8-byte integer + //fall through + case 'N': //fixed length numeric text field 1-262143 positions + $result = IElement::TYPE_INTEGER; break; - case 'IMPORT_STRUCT': - $param = $this->getParam($name, []); - foreach ($members as $member) { - if (!array_key_exists($member, $param)) { - $param[$member] = ''; - } - } - $result = @saprfc_import($this->function, $name, $param); + case 'P': //packed number 1-16 bytes + //fall through + case 'DECFLOAT16': //floating point with 16 positions + //fall through + case 'DECFLOAT34': //floating point with 34 positions + //fall through + case 'F': //binary floating point with 17 positions + $result = IElement::TYPE_FLOAT; break; - case 'TABLE': - $result = @saprfc_table_init($this->function, $name); + case 'C': //fixed length text field + //fall through + case 'STRING': //text string + $result = IElement::TYPE_STRING; + break; + case 'X': //hexadecimal encoded binary data + //fall through + case 'XSTRING': + $result = IElement::TYPE_STRING; + break; + case 'D': //date field + $result = IElement::TYPE_DATE; break; - case 'EXPORT': //fall through - case 'EXPORT_STRUCT': - $result = true; + case 'T': //time field + $result = IElement::TYPE_TIME; break; default: - throw new \LogicException(sprintf( - 'Unknown type %s in interface of function %s.', - $type, - $this->getName() - )); + throw new LogicException(sprintf('Unknown SAP data type \'%s\'!', $dataType)); } return $result; } /** - * Import results from the function call. - * @return array - * @throws \LogicException + * Convert SAPRFC type to PHP-SAP direction. + * @param string $type + * @return string + * @throws LogicException */ - private function getSaprfcResults() + private function typeToDirection($type) { - $result = []; - foreach ($this->getRemoteInterface() as $name => $definition) { - switch ($definition['type']) { - case 'IMPORT': //fall through - case 'IMPORT_STRUCT': - break; - case 'EXPORT': //fall through - case 'EXPORT_STRUCT': - $result[$name] = trim(@saprfc_export($this->function, $name)); - break; - case 'TABLE': - $result[$name] = []; - $max = @saprfc_table_rows($this->function, $this->getName()); - for ($index = 1; $index <= $max; $index++) { - $result[$name][] = @saprfc_table_read($this->function, $this->getName(), $index); - } - break; - default: - throw new \LogicException(sprintf( - 'Unknown type %s in interface of function %s.', - $definition['type'], - $this->getName() - )); - } + switch ($type) { + case 'IMPORT': + $result = IValue::DIRECTION_INPUT; + break; + case 'EXPORT': + $result = IValue::DIRECTION_OUTPUT; + break; + case 'TABLE': + $result = IArray::DIRECTION_TABLE; + break; + default: + throw new LogicException(sprintf('Unknown SAPRFC type \'%s\'!', $type)); } return $result; } From 5e6de7204059edc2dca01d13b5eb9559b0c5e289 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 31 Oct 2019 09:16:10 +0100 Subject: [PATCH 03/27] use dist trusty for php 5.5 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 9f607fb..849cffc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: php sudo: false +dist: trusty php: - 5.5 env: From 33abc238de375882f1b89aeb4feb8f0998bb6df1 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 11:39:47 +0100 Subject: [PATCH 04/27] composer update and require php-sap/datetime --- composer.lock | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.lock b/composer.lock index 4ee274a..6d709fa 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "14dcfc3d80466a4bac0825ac716c62e63977552c" + "reference": "6b8e2f69bc644184584a82ecf887b5369218530f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/14dcfc3d80466a4bac0825ac716c62e63977552c", - "reference": "14dcfc3d80466a4bac0825ac716c62e63977552c", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/6b8e2f69bc644184584a82ecf887b5369218530f", + "reference": "6b8e2f69bc644184584a82ecf887b5369218530f", "shasum": "" }, "require": { @@ -325,6 +325,7 @@ "kba-team/memory-container": "^1.0", "php": "^5.5", "php-sap/common": "v3.x-dev", + "php-sap/datetime": "^1.1", "php-sap/interfaces": "v2.x-dev", "phpunit/phpunit": "^4.8" }, @@ -347,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-10-30T16:23:49+00:00" + "time": "2019-11-04T10:14:16+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -1367,16 +1368,16 @@ }, { "name": "symfony/yaml", - "version": "v3.4.32", + "version": "v3.4.33", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "768f817446da74a776a31eea335540f9dcb53942" + "reference": "dab657db15207879217fc81df4f875947bf68804" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/768f817446da74a776a31eea335540f9dcb53942", - "reference": "768f817446da74a776a31eea335540f9dcb53942", + "url": "https://api.github.com/repos/symfony/yaml/zipball/dab657db15207879217fc81df4f875947bf68804", + "reference": "dab657db15207879217fc81df4f875947bf68804", "shasum": "" }, "require": { @@ -1422,7 +1423,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-09-10T10:38:46+00:00" + "time": "2019-10-24T15:33:53+00:00" }, { "name": "webmozart/assert", From 9c8a0922701761736afe29ebbde2968643a8f5f0 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 11:41:09 +0100 Subject: [PATCH 05/27] rewrite tests for new integration tests Tests now cover tables as parameters too. --- src/SapRfcFunction.php | 241 +++++---- tests/SapRfcFunctionTest.php | 994 +++++++++++++++------------------- tests/SapRfcTestCaseTrait.php | 3 + tests/helper/saprfc.php | 13 + 4 files changed, 598 insertions(+), 653 deletions(-) diff --git a/src/SapRfcFunction.php b/src/SapRfcFunction.php index 7b89f34..44f6262 100644 --- a/src/SapRfcFunction.php +++ b/src/SapRfcFunction.php @@ -20,11 +20,11 @@ use phpsap\classes\Api\Value; use phpsap\classes\RemoteApi; use phpsap\exceptions\FunctionCallException; +use phpsap\exceptions\SapException; use phpsap\exceptions\UnknownFunctionException; use phpsap\interfaces\Api\IArray; use phpsap\interfaces\Api\IElement; use phpsap\interfaces\Api\IValue; -use phpsap\interfaces\IApi; use phpsap\interfaces\IFunction; /** @@ -49,17 +49,10 @@ class SapRfcFunction extends AbstractFunction */ protected $function; - /** - * SAP remote function interface. - * @var mixed - */ - private $functionInterface; - /** * Invoke the prepared function call. * @return array * @throws FunctionCallException - * @throws LogicException */ public function invoke() { @@ -80,9 +73,6 @@ public function invoke() */ public function __destruct() { - if ($this->functionInterface !== null) { - $this->functionInterface = null; - } if ($this->function !== null) { @saprfc_function_free($this->function); $this->function = null; @@ -126,43 +116,108 @@ protected function getFunction() /** * Export all function call parameters. - * @throws LogicException + * @return void * @throws FunctionCallException */ private function setSaprfcParameters() { - foreach ($this->getApi()->getInputValues() as $input) { + $this->setSapRfcInputValues($this->getApi()->getInputValues()); + $this->setSapRfcTables($this->getApi()->getTables()); + } + + /** + * Set all input values. + * @param array $inputs The array of input parameters to set. + * @return void + * @throws FunctionCallException + */ + private function setSapRfcInputValues($inputs) + { + foreach ($inputs as $input) { $name = $input->getName(); $value = $this->getParam($name); - if ($value === null && !$input->isOptional()) { + if (!$this->setSapRfcInputValue($name, $value, $input->isOptional())) { throw new FunctionCallException(sprintf( - 'Missing parameter \'%s\' for function call \'%s\'!', + 'Function call %s failed: Assigning param %s, expected type %s, actual type %s failed.', + $this->getName(), $name, - $this->getName() + $input->getType(), + gettype($value) )); } - $result = @saprfc_import($this->function, $name, $value); + } + } + + /** + * Set a single input parameter value for the function call. + * @param string $name The name of the parameter. + * @param mixed $value The value of the parameter. + * @param bool $isOptional Is the parameter optional (TRUE) or mandatory (FALSE)? + * @return bool Has the parameter been set successfully? + * @throws FunctionCallException in case the parameter value is null but mandatory. + */ + private function setSapRfcInputValue($name, $value, $isOptional) + { + if ($value === null && !$isOptional) { + throw new FunctionCallException(sprintf( + 'Missing parameter \'%s\' for function call \'%s\'!', + $name, + $this->getName() + )); + } + if ($value === null) { + return true; + } + return @saprfc_import($this->function, $name, $value); + } + + /** + * Initializes the table parameters of the remote function call. + * @param array $tables The array of table parameters to initialize. + * @return void + * @throws FunctionCallException In case the initialization fails. + */ + private function setSapRfcTables($tables) + { + foreach ($tables as $table) { + $name = $table->getName(); + $result = $this->setSapRfcTable($name, $this->getParam($name)); if ($result !== true) { - throw new LogicException(sprintf( - 'Assigning param %s, expected type %s, actual type %s to function %s failed.', + throw new FunctionCallException(sprintf( + 'Initializing table %s for function %s failed!', $name, - $input->getType(), - gettype($value), $this->getName() )); } } + } - foreach ($this->getApi()->getTables() as $table) { - $result = @saprfc_table_init($this->function, $table->getName()); - if ($result !== true) { - throw new LogicException(sprintf( - 'Initializing table %s for function %s failed.', - $table->getName(), + /** + * Initialize a remote function call table and add rows, in case there are rows. + * @param string $name The table name to initialize and fill. + * @param array $rows The rows to add to the table. + * @return bool Init success? + * @throws FunctionCallException + */ + private function setSapRfcTable($name, $rows) + { + if (!@saprfc_table_init($this->function, $name)) { + return false; + } + if (!is_array($rows)) { + return true; + } + foreach ($rows as $number => $row) { + if (!@saprfc_table_append($this->function, $name, $row)) { + throw new FunctionCallException(sprintf( + 'Adding row #%u to table %s for function %s failed!', + $number, + $name, $this->getName() )); } } + return true; } /** @@ -175,7 +230,7 @@ private function getSaprfcResults() foreach ($this->getApi()->getOutputValues() as $output) { $name = $output->getName(); $value = @saprfc_export($this->function, $name); - $result[$name] = $output->cast(trim($value)); + $result[$name] = $output->cast($value); unset($name, $value); } foreach ($this->getApi()->getTables() as $table) { @@ -193,9 +248,10 @@ private function getSaprfcResults() /** * Extract the remote function API and return an API description class. - * @return IApi + * @return RemoteApi The remote API description class. * @throws InvalidArgumentException - * @throws LogicException + * @throws LogicException In case the given SAP RFC type is missing in the static mapping. + * @throws SapException In case of a general error where the remote function API cannot be queried. */ public function extractApi() { @@ -212,25 +268,27 @@ public function extractApi() } /** - * Get remote function call interface definition. - * @return array + * Get remote function call API definition. + * @return array The array describing the remote function call API. + * @throws SapException In case of a general error where the remote function API cannot be queried. */ - private function saprfcFunctionInterface() + public function saprfcFunctionInterface() { $definitions = @saprfc_function_interface($this->function); if ($definitions === false) { - return []; + throw new SapException('Cannot query remote function API!'); } return $definitions; } /** - * @param string $name - * @param string $direction - * @param bool $optional - * @param array $def - * @return IValue - * @throws LogicException + * Create either Value, Struct or Table from a given remote function parameter or return value. + * @param string $name The name of the parameter or return value. + * @param string $direction The direction indicating whether it's a parameter or return value. + * @param bool $optional The flag, whether this parameter or return value is required. + * @param array $def The parameter or return value definition containing the data type. + * @return Value|Struct|Table + * @throws LogicException In case a datatype is missing in the mappings array. */ private function createApiValue($name, $direction, $optional, $def) { @@ -244,10 +302,10 @@ private function createApiValue($name, $direction, $optional, $def) } /** - * Create members from the def array. + * Create either struct or table members from the def array of the remote function API. * @param array $members - * @return array - * @throws LogicException + * @return Element[] An array of IElement compatible objects. + * @throws LogicException In case a datatype is missing in the mappings array. */ private function createMembers($members) { @@ -260,76 +318,51 @@ private function createMembers($members) /** * Convert SAPRFC abap datatype to PHP-SAP datatype. - * @param string $dataType - * @return string - * @throws LogicException + * @param string $type The ABAP data type from the API definition. + * @return string The PHP/SAP internal data type. + * @throws LogicException In case a datatype is missing in the mappings array. */ - private function abapToType($dataType) + private function abapToType($type) { - switch ($dataType) { - case 'B': //1-byte integer (internal) - //fall through - case 'S': //2-byte integer (internal) - //fall through - case 'I': //4-byte integer - //fall through - case 'INT8': //8-byte integer - //fall through - case 'N': //fixed length numeric text field 1-262143 positions - $result = IElement::TYPE_INTEGER; - break; - case 'P': //packed number 1-16 bytes - //fall through - case 'DECFLOAT16': //floating point with 16 positions - //fall through - case 'DECFLOAT34': //floating point with 34 positions - //fall through - case 'F': //binary floating point with 17 positions - $result = IElement::TYPE_FLOAT; - break; - case 'C': //fixed length text field - //fall through - case 'STRING': //text string - $result = IElement::TYPE_STRING; - break; - case 'X': //hexadecimal encoded binary data - //fall through - case 'XSTRING': - $result = IElement::TYPE_STRING; - break; - case 'D': //date field - $result = IElement::TYPE_DATE; - break; - case 'T': //time field - $result = IElement::TYPE_TIME; - break; - default: - throw new LogicException(sprintf('Unknown SAP data type \'%s\'!', $dataType)); + static $mapping = [ + 'b' => IElement::TYPE_INTEGER, //1-byte integer (internal) + 's' => IElement::TYPE_INTEGER, //2-byte integer (internal) + 'I' => IElement::TYPE_INTEGER, //4-byte integer + 'INT8' => IElement::TYPE_INTEGER, //8-byte integer + 'P' => IElement::TYPE_FLOAT, //packed number 1-16 bytes + 'DECFLOAT16' => IElement::TYPE_FLOAT, //floating point with 16 positions + 'DECFLOAT34' => IElement::TYPE_FLOAT, //floating point with 34 positions + 'F' => IElement::TYPE_FLOAT, //binary floating point with 17 positions + 'C' => IElement::TYPE_STRING, //fixed length text field + 'N' => IElement::TYPE_INTEGER, //fixed length numeric text field 1-262143 positions + 'STRING' => IElement::TYPE_STRING, //text string + 'X' => IElement::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data + 'XSTRING' => IElement::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data + 'D' => IElement::TYPE_DATE, //date field + 'T' => IElement::TYPE_TIME, //time field + ]; + if (!array_key_exists($type, $mapping)) { + throw new LogicException(sprintf('Unknown SAP data type \'%s\'!', $type)); } - return $result; + return $mapping[$type]; } /** - * Convert SAPRFC type to PHP-SAP direction. - * @param string $type - * @return string - * @throws LogicException + * Convert SAPRFC type to PHP/SAP direction. + * @param string $type The remote function parameter type indicating whether it's an input or a return parameter. + * @return string The PHP/SAP internal direction. + * @throws LogicException In case the given SAP RFC type is missing in the static mapping. */ private function typeToDirection($type) { - switch ($type) { - case 'IMPORT': - $result = IValue::DIRECTION_INPUT; - break; - case 'EXPORT': - $result = IValue::DIRECTION_OUTPUT; - break; - case 'TABLE': - $result = IArray::DIRECTION_TABLE; - break; - default: - throw new LogicException(sprintf('Unknown SAPRFC type \'%s\'!', $type)); + static $mapping = [ + 'IMPORT' => IValue::DIRECTION_INPUT, //SAP remote function input parameter + 'EXPORT' => IValue::DIRECTION_OUTPUT, //SAP remote function return value or struct + 'TABLE' => IArray::DIRECTION_TABLE //SAP remote function return table + ]; + if (!array_key_exists($type, $mapping)) { + throw new LogicException(sprintf('Unknown SAPRFC type \'%s\'!', $type)); } - return $result; + return $mapping[$type]; } } diff --git a/tests/SapRfcFunctionTest.php b/tests/SapRfcFunctionTest.php index 06ca96b..8bf1b5b 100644 --- a/tests/SapRfcFunctionTest.php +++ b/tests/SapRfcFunctionTest.php @@ -24,6 +24,376 @@ */ class SapRfcFunctionTest extends AbstractFunctionTestCase { + public static $rfcWalkThruTestApi = [ + [ + 'name' => 'TEST_OUT', + 'type' => 'EXPORT', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'RFCFLOAT', + 'abap' => 'F', + 'len' => 8, + 'dec' => 0, + 'offset' => 0 + ], + [ + 'name' => 'RFCCHAR1', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 8 + ], + [ + 'name' => 'RFCINT2', + 'abap' => 's', + 'len' => 2, + 'dec' => 0, + 'offset' => 10 + ], + [ + 'name' => 'RFCINT1', + 'abap' => 'b', + 'len' => 1, + 'dec' => 0, + 'offset' => 12 + ], + [ + 'name' => 'RFCCHAR4', + 'abap' => 'C', + 'len' => 4, + 'dec' => 0, + 'offset' => 13 + ], + [ + 'name' => 'RFCINT4', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 20 + ], + [ + 'name' => 'RFCHEX3', + 'abap' => 'X', + 'len' => 3, + 'dec' => 0, + 'offset' => 24 + ], + [ + 'name' => 'RFCCHAR2', + 'abap' => 'C', + 'len' => 2, + 'dec' => 0, + 'offset' => 27 + ], + [ + 'name' => 'RFCTIME', + 'abap' => 'T', + 'len' => 6, + 'dec' => 0, + 'offset' => 29 + ], + [ + 'name' => 'RFCDATE', + 'abap' => 'D', + 'len' => 8, + 'dec' => 0, + 'offset' => 35 + ], + [ + 'name' => 'RFCDATA1', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 43 + ], + [ + 'name' => 'RFCDATA2', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 93 + ] + ] + ], + [ + 'name' => 'TEST_IN', + 'type' => 'IMPORT', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'RFCFLOAT', + 'abap' => 'F', + 'len' => 8, + 'dec' => 0, + 'offset' => 0 + ], + [ + 'name' => 'RFCCHAR1', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 8 + ], + [ + 'name' => 'RFCINT2', + 'abap' => 's', + 'len' => 2, + 'dec' => 0, + 'offset' => 10 + ], + [ + 'name' => 'RFCINT1', + 'abap' => 'b', + 'len' => 1, + 'dec' => 0, + 'offset' => 12 + ], + [ + 'name' => 'RFCCHAR4', + 'abap' => 'C', + 'len' => 4, + 'dec' => 0, + 'offset' => 13 + ], + [ + 'name' => 'RFCINT4', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 20 + ], + [ + 'name' => 'RFCHEX3', + 'abap' => 'X', + 'len' => 3, + 'dec' => 0, + 'offset' => 24 + ], + [ + 'name' => 'RFCCHAR2', + 'abap' => 'C', + 'len' => 2, + 'dec' => 0, + 'offset' => 27 + ], + [ + 'name' => 'RFCTIME', + 'abap' => 'T', + 'len' => 6, + 'dec' => 0, + 'offset' => 29 + ], + [ + 'name' => 'RFCDATE', + 'abap' => 'D', + 'len' => 8, + 'dec' => 0, + 'offset' => 35 + ], + [ + 'name' => 'RFCDATA1', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 43 + ], + [ + 'name' => 'RFCDATA2', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 93 + ] + ] + ], + [ + 'name' => 'DESTINATIONS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'RFCDEST', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 0 + ] + ] + ], + [ + 'name' => 'LOG', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'RFCDEST', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 0 + ], + [ + 'name' => 'RFCWHOAMI', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 32 + ], + [ + 'name' => 'RFCLOG', + 'abap' => 'C', + 'len' => 70, + 'dec' => 0, + 'offset' => 64 + ] + ] + ] + ]; + + public static $rfcReadTableApi = [ + [ + 'name' => 'DELIMITER', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => [ + [ + 'name' => '', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'NO_DATA', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => [ + [ + 'name' => '', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'QUERY_TABLE', + 'type' => 'IMPORT', + 'optional' => 0, + 'def' => [ + [ + 'name' => '', + 'abap' => 'C', + 'len' => 30, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'ROWCOUNT', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => [ + [ + 'name' => '', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'ROWSKIPS', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => [ + [ + 'name' => '', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'DATA', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'WA', + 'abap' => 'C', + 'len' => 512, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + [ + 'name' => 'FIELDS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'FIELDNAME', + 'abap' => 'C', + 'len' => 30, + 'dec' => 0, + 'offset' => 0, + ], + [ + 'name' => 'OFFSET', + 'abap' => 'N', + 'len' => 6, + 'dec' => 0, + 'offset' => 30, + ], + [ + 'name' => 'LENGTH', + 'abap' => 'N', + 'len' => 6, + 'dec' => 0, + 'offset' => 36, + ], + [ + 'name' => 'TYPE', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 42, + ], + [ + 'name' => 'FIELDTEXT', + 'abap' => 'C', + 'len' => 60, + 'dec' => 0, + 'offset' => 43, + ], + ], + ], + [ + 'name' => 'OPTIONS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => [ + [ + 'name' => 'TEXT', + 'abap' => 'C', + 'len' => 72, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + ]; + /** * Implements methods of phpsap\IntegrationTests\AbstractTestCase */ @@ -58,7 +428,10 @@ protected function mockSuccessfulFunctionCall() static::mock('saprfc_function_free', function (&$function) { $function = null; }); - static::mock('saprfc_function_interface', function () { + static::mock('saprfc_function_interface', function ($function) { + if ($function === 'SAPRFC PING') { + return []; + } return false; }); } @@ -107,316 +480,88 @@ protected function mockRemoteFunctionCallWithParametersAndResults() $connection = null; }); static::mock('saprfc_function_discover', function ($connection, $name) { - if ($connection === 'SAPRFC CONNECTION' && $name === 'Z_MC_GET_DATE_TIME') { - return 'SAPRFC Z_MC_GET_DATE_TIME'; + if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_WALK_THRU_TEST') { + return 'SAPRFC RFC_WALK_THRU_TEST'; } return false; }); static::mock('saprfc_function_interface', function ($function) { - if ($function === 'SAPRFC Z_MC_GET_DATE_TIME') { - return [ - 0 => [ - 'name' => 'EV_FRIDAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 1 => [ - 'name' => 'EV_FRIDAY_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 2 => [ - 'name' => 'EV_FRIDAY_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 3 => [ - 'name' => 'EV_FRITXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'C', - 'len' => 15, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 4 => [ - 'name' => 'EV_MONDAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 5 => [ - 'name' => 'EV_MONDAY_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 6 => [ - 'name' => 'EV_MONDAY_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 7 => [ - 'name' => 'EV_MONTH', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 2, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 8 => [ - 'name' => 'EV_MONTH_LAST_DAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 9 => [ - 'name' => 'EV_MONTXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'C', - 'len' => 15, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 10 => [ - 'name' => 'EV_TIMESTAMP', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'C', - 'len' => 14, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 11 => [ - 'name' => 'EV_WEEK', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 12 => [ - 'name' => 'EV_WEEK_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 13 => [ - 'name' => 'EV_WEEK_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 14 => [ - 'name' => 'EV_YEAR', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 4, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 15 => [ - 'name' => 'IV_DATE', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - ]; + if ($function === 'SAPRFC RFC_WALK_THRU_TEST') { + return static::$rfcWalkThruTestApi; } return false; }); static::mock('saprfc_call_and_receive', function ($function) { - if ($function === 'SAPRFC Z_MC_GET_DATE_TIME') { + if ($function === 'SAPRFC RFC_WALK_THRU_TEST') { return 0; } return 1; }); static::mock('saprfc_import', function ($function, $name, $param) { - return ($function === 'SAPRFC Z_MC_GET_DATE_TIME' - && $name === 'IV_DATE' - && $param === '20181119' + return ($function === 'SAPRFC RFC_WALK_THRU_TEST' + && $name === 'TEST_IN' + && is_array($param) ); }); - static::mock('saprfc_export', function ($function, $name) { - if ($function !== 'SAPRFC Z_MC_GET_DATE_TIME') { - return ''; + static::mock('saprfc_table_init', function ($function, $name) { + return ($function === 'SAPRFC RFC_WALK_THRU_TEST' + && in_array($name, ['LOG', 'DESTINATIONS']) + ); + }); + static::mock('saprfc_table_append', function ($function, $name, $param) { + return ($function === 'SAPRFC RFC_WALK_THRU_TEST' + && $name === 'DESTINATIONS' + && is_array($param) + ); + }); + static::mock('saprfc_table_append', function ($function, $name, $param) { + return ($function === 'SAPRFC RFC_WALK_THRU_TEST' + && $name === 'DESTINATIONS' + && is_array($param) + && $param === ['RFCDEST' => 'AOP3'] + ); + }); + static::mock('saprfc_table_rows', function ($function, $name) { + if ($function !== 'SAPRFC RFC_WALK_THRU_TEST') { + return false; } switch ($name) { - case 'EV_FRIDAY': - return '20181123'; - case 'EV_FRIDAY_LAST': - return '20181116'; - case 'EV_FRIDAY_NEXT': - return '20181130'; - case 'EV_FRITXT': - return 'Freitag'; - case 'EV_MONDAY': - return '20181119'; - case 'EV_MONDAY_LAST': - return '20181112'; - case 'EV_MONDAY_NEXT': - return '20181126'; - case 'EV_MONTH': - return '11'; - case 'EV_MONTH_LAST_DAY': - return '20181130'; - case 'EV_MONTXT': - return 'Montag'; - case 'EV_TIMESTAMP': - return '201811190000000'; - case 'EV_WEEK': - return '201847'; - case 'EV_WEEK_LAST': - return '201846'; - case 'EV_WEEK_NEXT': - return '201848'; - case 'EV_YEAR': - return '2018'; + case 'LOG': + return 1; + case 'DESTINATIONS': + return 0; default: - return ''; + return false; + } + }); + static::mock('saprfc_table_read', function ($function, $name, $param) { + if ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'LOG' && $param === 1) { + return [ + 'RFCDEST' => 'AOP3', + 'RFCWHOAMI' => 'pzjti000', + 'RFCLOG' => 'FAP-RytEHBsRYKX AOP3 eumqvMJD ZLqovj.' //just some random characters around AOP3 + ]; + } + return false; + }); + static::mock('saprfc_export', function ($function, $name) { + if ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'TEST_OUT') { + return [ + 'RFCFLOAT' => 70.11, + 'RFCCHAR1' => 'A', + 'RFCINT2' => 5920, + 'RFCINT1' => 163, + 'RFCCHAR4' => 'QqMh', + 'RFCINT4' => 416639, + 'RFCHEX3' => '53', //=S + 'RFCCHAR2' => 'XC', + 'RFCTIME' => '102030', + 'RFCDATE' => '20191030', + 'RFCDATA1' => 'qKWjmNfad32rfS9Z', + 'RFCDATA2' => 'xi82ph2zJ8BCVtlR' + ]; } + return false; }); static::mock('saprfc_function_free', function (&$function) { $function = null; @@ -438,276 +583,27 @@ protected function mockFailedRemoteFunctionCallWithParameters() $connection = null; }); static::mock('saprfc_function_discover', function ($connection, $name) { - if ($connection === 'SAPRFC CONNECTION' && $name === 'Z_MC_GET_DATE_TIME') { - return 'SAPRFC Z_MC_GET_DATE_TIME'; + if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_READ_TABLE') { + return 'SAPRFC RFC_READ_TABLE'; } return false; }); static::mock('saprfc_function_interface', function ($function) { - if ($function === 'SAPRFC Z_MC_GET_DATE_TIME') { - return [ - 0 => [ - 'name' => 'EV_FRIDAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 1 => [ - 'name' => 'EV_FRIDAY_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 2 => [ - 'name' => 'EV_FRIDAY_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 3 => [ - 'name' => 'EV_FRITXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - 0 => [ - 'name' => '', - 'abap' => 'C', - 'len' => 15, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 4 => [ - 'name' => 'EV_MONDAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 5 => [ - 'name' => 'EV_MONDAY_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 6 => [ - 'name' => 'EV_MONDAY_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 7 => [ - 'name' => 'EV_MONTH', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 2, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 8 => [ - 'name' => 'EV_MONTH_LAST_DAY', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 9 => [ - 'name' => 'EV_MONTXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'C', - 'len' => 15, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 10 => [ - 'name' => 'EV_TIMESTAMP', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'C', - 'len' => 14, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 11 => [ - 'name' => 'EV_WEEK', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 12 => [ - 'name' => 'EV_WEEK_LAST', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 13 => [ - 'name' => 'EV_WEEK_NEXT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 14 => [ - 'name' => 'EV_YEAR', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'N', - 'len' => 4, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - 15 => [ - 'name' => 'IV_DATE', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => - [ - 0 => - [ - 'name' => '', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 0, - ], - ], - ], - ]; + if ($function === 'SAPRFC RFC_READ_TABLE') { + return static::$rfcReadTableApi; } return false; }); static::mock('saprfc_call_and_receive', function ($function) { - if ($function === 'SAPRFC Z_MC_GET_DATE_TIME') { + if ($function === 'SAPRFC RFC_READ_TABLE') { return 1; } throw new \RuntimeException('Unexpected function instance.'); }); static::mock('saprfc_import', function ($function, $name, $param) { - return ($function === 'SAPRFC Z_MC_GET_DATE_TIME' - && $name === 'IV_DATE' - && $param === '2018-11-19' + return ($function === 'SAPRFC RFC_READ_TABLE' + && $name === 'QUERY_TABLE' + && $param === '' ); }); static::mock('saprfc_function_free', function (&$function) { diff --git a/tests/SapRfcTestCaseTrait.php b/tests/SapRfcTestCaseTrait.php index f3754e0..d0524fa 100644 --- a/tests/SapRfcTestCaseTrait.php +++ b/tests/SapRfcTestCaseTrait.php @@ -69,6 +69,7 @@ public function getValidModuleFunctions() 'saprfc_function_interface', 'saprfc_import', 'saprfc_table_init', + 'saprfc_table_append', 'saprfc_export', 'saprfc_table_rows', 'saprfc_table_read' @@ -79,6 +80,8 @@ public function getValidModuleFunctions() * Create a new instance of a PHP/SAP connection class. * @param array|string|null $config The PHP/SAP configuration. Default: null * @return \phpsap\saprfc\SapRfcConnection + * @throws \InvalidArgumentException + * @throws \phpsap\interfaces\exceptions\IIncompleteConfigException */ public function newConnection($config = null) { diff --git a/tests/helper/saprfc.php b/tests/helper/saprfc.php index a4f539d..6719bd6 100644 --- a/tests/helper/saprfc.php +++ b/tests/helper/saprfc.php @@ -125,6 +125,19 @@ function saprfc_table_init($function, $name) return $func($function, $name); } +/** + * Initialize saprfc table. + * @param resource $function The remote function call resource. + * @param string $name The parameter name. + * @param array $row The table row to add. + * @return bool + */ +function saprfc_table_append($function, $name, $row) +{ + $func = \phpsap\IntegrationTests\SapRfcModuleMocks::singleton()->get(__FUNCTION__); + return $func($function, $name, $row); +} + /** * Get function call result. * @param resource $function The remote function call resource. From c34715f5436a8ac3c2fca35bab3db8bf815e2c49 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 11:45:01 +0100 Subject: [PATCH 06/27] clean-up classpaths --- src/SapRfcConfigTrait.php | 2 +- src/SapRfcConnection.php | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/SapRfcConfigTrait.php b/src/SapRfcConfigTrait.php index 29ccf46..81cce35 100644 --- a/src/SapRfcConfigTrait.php +++ b/src/SapRfcConfigTrait.php @@ -27,7 +27,7 @@ trait SapRfcConfigTrait * Generate the configuration array needed for connecting a remote SAP system * using Eduard Kouckys saprfc module. * @return array - * @throws \phpsap\exceptions\IncompleteConfigException + * @throws IncompleteConfigException */ public function generateConfig() { diff --git a/src/SapRfcConnection.php b/src/SapRfcConnection.php index a089c1d..9f87878 100644 --- a/src/SapRfcConnection.php +++ b/src/SapRfcConnection.php @@ -14,6 +14,7 @@ use phpsap\classes\AbstractConnection; use phpsap\exceptions\ConnectionFailedException; use phpsap\exceptions\FunctionCallException; +use phpsap\exceptions\UnknownFunctionException; /** * Class phpsap\saprfc\SapRfcConnection @@ -31,7 +32,8 @@ class SapRfcConnection extends AbstractConnection * Send a ping request via an established connection to verify that the * connection works. * @return boolean success? - * @throws \phpsap\exceptions\ConnectionFailedException + * @throws ConnectionFailedException + * @throws UnknownFunctionException */ public function ping() { @@ -58,8 +60,9 @@ public function close() /** * Prepare a remote function call and return a function instance. * @param string $name - * @return \phpsap\saprfc\SapRfcFunction - * @throws \phpsap\exceptions\ConnectionFailedException + * @return SapRfcFunction + * @throws ConnectionFailedException + * @throws UnknownFunctionException */ protected function createFunctionInstance($name) { @@ -68,7 +71,7 @@ protected function createFunctionInstance($name) /** * Creates a connection using the underlying PHP module. - * @throws \phpsap\exceptions\ConnectionFailedException + * @throws ConnectionFailedException */ public function connect() { From 6daa4f5be795384599e8c28e4e1c804c27968cc8 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 12:54:03 +0100 Subject: [PATCH 07/27] update php-sap/common to fix failing test --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 6d709fa..febe60d 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "f0f53674fa83d49f95402e3424dab0d863eae051" + "reference": "802dcb42a7141a37fede8229eed0a818977f4844" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/f0f53674fa83d49f95402e3424dab0d863eae051", - "reference": "f0f53674fa83d49f95402e3424dab0d863eae051", + "url": "https://api.github.com/repos/php-sap/common/zipball/802dcb42a7141a37fede8229eed0a818977f4844", + "reference": "802dcb42a7141a37fede8229eed0a818977f4844", "shasum": "" }, "require": { @@ -54,7 +54,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-10-30T15:37:41+00:00" + "time": "2019-11-04T11:28:56+00:00" }, { "name": "php-sap/datetime", From ef7cf5f3555f794947bcd213fae87bd3b43323cd Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 13:00:44 +0100 Subject: [PATCH 08/27] exclude all JSON files in config dir except the template --- tests/config/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/config/.gitignore b/tests/config/.gitignore index ce13eb5..5860550 100644 --- a/tests/config/.gitignore +++ b/tests/config/.gitignore @@ -1 +1,2 @@ -sap.json +*.json +!sap.template.json From e5b62c30f72c2b28de097b491294935952ca7d7e Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 4 Nov 2019 13:01:14 +0100 Subject: [PATCH 09/27] update readme to coming version --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aed9ca6..e6bd74e 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This repository implements the [PHP/SAP][phpsap] interface for [Eduard Kouckys l ## Usage ```sh -composer require php-sap/saprfc-koucky:^1.0 +composer require php-sap/saprfc-koucky:^2.0 ``` ```php @@ -26,7 +26,8 @@ $result = (new SapRfcConnection(new SapRfcConfigA([ 'passwd' => 'password' ]))) ->prepareFunction('MY_COOL_SAP_REMOTE_FUNCTION') - ->invoke(['INPUT_PARAM' => 'value']); + ->setParam('INPUT_PARAM', 'some input value') + ->invoke(); ``` For further documentation, please read the documentation on [PHP/SAP][phpsap]! From e3ae3000203dac683892f7a9fabde9ac87480243 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 7 Nov 2019 13:51:26 +0100 Subject: [PATCH 10/27] update php-sap/integration-tests --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index febe60d..f137408 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "6b8e2f69bc644184584a82ecf887b5369218530f" + "reference": "68bb63376db160b9be2101f7fa79dce4314c35d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/6b8e2f69bc644184584a82ecf887b5369218530f", - "reference": "6b8e2f69bc644184584a82ecf887b5369218530f", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/68bb63376db160b9be2101f7fa79dce4314c35d0", + "reference": "68bb63376db160b9be2101f7fa79dce4314c35d0", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-11-04T10:14:16+00:00" + "time": "2019-11-07T12:36:41+00:00" }, { "name": "phpdocumentor/reflection-common", From f6bf276342338bbc1a6b9ab2c4586963ceaa4128 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 7 Nov 2019 15:11:32 +0100 Subject: [PATCH 11/27] update php-sap/common and integration-tests --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index f137408..b176544 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "802dcb42a7141a37fede8229eed0a818977f4844" + "reference": "04ef97848b7b7ab17c3e076d63604ece94dab0a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/802dcb42a7141a37fede8229eed0a818977f4844", - "reference": "802dcb42a7141a37fede8229eed0a818977f4844", + "url": "https://api.github.com/repos/php-sap/common/zipball/04ef97848b7b7ab17c3e076d63604ece94dab0a9", + "reference": "04ef97848b7b7ab17c3e076d63604ece94dab0a9", "shasum": "" }, "require": { @@ -54,7 +54,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-11-04T11:28:56+00:00" + "time": "2019-11-07T13:50:01+00:00" }, { "name": "php-sap/datetime", @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "68bb63376db160b9be2101f7fa79dce4314c35d0" + "reference": "b15b6411b42ca970bf76b5527ddb8c16059f8c5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/68bb63376db160b9be2101f7fa79dce4314c35d0", - "reference": "68bb63376db160b9be2101f7fa79dce4314c35d0", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/b15b6411b42ca970bf76b5527ddb8c16059f8c5c", + "reference": "b15b6411b42ca970bf76b5527ddb8c16059f8c5c", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-11-07T12:36:41+00:00" + "time": "2019-11-07T14:05:22+00:00" }, { "name": "phpdocumentor/reflection-common", From cc581ce8a2bb8bbbcdff126bc7ae0695933a82ba Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 7 Nov 2019 16:24:54 +0100 Subject: [PATCH 12/27] tests: change ABAP type 's' number to 4095 --- composer.lock | 8 ++++---- tests/SapRfcFunctionTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index b176544..a94a1cf 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "b15b6411b42ca970bf76b5527ddb8c16059f8c5c" + "reference": "85d0daf4be496a25386dcf38a2512b2a340e8cdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/b15b6411b42ca970bf76b5527ddb8c16059f8c5c", - "reference": "b15b6411b42ca970bf76b5527ddb8c16059f8c5c", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/85d0daf4be496a25386dcf38a2512b2a340e8cdb", + "reference": "85d0daf4be496a25386dcf38a2512b2a340e8cdb", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-11-07T14:05:22+00:00" + "time": "2019-11-07T15:20:35+00:00" }, { "name": "phpdocumentor/reflection-common", diff --git a/tests/SapRfcFunctionTest.php b/tests/SapRfcFunctionTest.php index 8bf1b5b..e9f9278 100644 --- a/tests/SapRfcFunctionTest.php +++ b/tests/SapRfcFunctionTest.php @@ -549,7 +549,7 @@ protected function mockRemoteFunctionCallWithParametersAndResults() return [ 'RFCFLOAT' => 70.11, 'RFCCHAR1' => 'A', - 'RFCINT2' => 5920, + 'RFCINT2' => 4095, 'RFCINT1' => 163, 'RFCCHAR4' => 'QqMh', 'RFCINT4' => 416639, From 2abc8f6492d821668962c4356be5d7a97bb8f154 Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 7 Nov 2019 17:10:33 +0100 Subject: [PATCH 13/27] remove AbstractRemoteFunctionCall --- composer.lock | 8 ++-- src/AbstractRemoteFunctionCall.php | 39 ----------------- tests/AbstractRemoteFunctionCallTest.php | 45 -------------------- tests/helper/RemoteFunctionCall.php | 53 ------------------------ 4 files changed, 4 insertions(+), 141 deletions(-) delete mode 100644 src/AbstractRemoteFunctionCall.php delete mode 100644 tests/AbstractRemoteFunctionCallTest.php delete mode 100644 tests/helper/RemoteFunctionCall.php diff --git a/composer.lock b/composer.lock index a94a1cf..3d9108d 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "04ef97848b7b7ab17c3e076d63604ece94dab0a9" + "reference": "7f331e9b2cb02591ac27ed17353109b18b9adcb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/04ef97848b7b7ab17c3e076d63604ece94dab0a9", - "reference": "04ef97848b7b7ab17c3e076d63604ece94dab0a9", + "url": "https://api.github.com/repos/php-sap/common/zipball/7f331e9b2cb02591ac27ed17353109b18b9adcb9", + "reference": "7f331e9b2cb02591ac27ed17353109b18b9adcb9", "shasum": "" }, "require": { @@ -54,7 +54,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-11-07T13:50:01+00:00" + "time": "2019-11-07T16:06:35+00:00" }, { "name": "php-sap/datetime", diff --git a/src/AbstractRemoteFunctionCall.php b/src/AbstractRemoteFunctionCall.php deleted file mode 100644 index f2255e8..0000000 --- a/src/AbstractRemoteFunctionCall.php +++ /dev/null @@ -1,39 +0,0 @@ - 'sap.example.com', - 'sysnr' => '001', - 'client' => '002', - 'user' => 'username', - 'passwd' => 'password' - ]); - $rfc = new RemoteFunctionCall($config); - $connection = $rfc->createConnectionInstance($config); - static::assertInstanceOf(SapRfcConnection::class, $connection); - } -} diff --git a/tests/helper/RemoteFunctionCall.php b/tests/helper/RemoteFunctionCall.php deleted file mode 100644 index 2c792df..0000000 --- a/tests/helper/RemoteFunctionCall.php +++ /dev/null @@ -1,53 +0,0 @@ -returnName; - } - - /** - * Make protected function public for testing. - * Create a connection instance using the given config. - * @param \phpsap\interfaces\IConfig $config - * @return \phpsap\interfaces\IConnection|\phpsap\saprfc\SapRfcConnection - * @throws \phpsap\interfaces\exceptions\IIncompleteConfigException - */ - public function createConnectionInstance(IConfig $config) - { - return parent::createConnectionInstance($config); - } -} From 4f42859d6668a5f9e6f7c2478aab9a09e4c5c82f Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 28 Nov 2019 14:22:42 +0100 Subject: [PATCH 14/27] update to v2 connection interface * Removed module specific configuration classes and tests. * Adapted connection class and tests to v2 interface. * Updated composer packages to v3 integration tests. --- composer.json | 2 +- composer.lock | 60 +++++----- src/SapRfcConfigA.php | 44 ------- src/SapRfcConfigB.php | 43 ------- src/SapRfcConfigTrait.php | 49 -------- src/SapRfcConnection.php | 209 +++++++++++++++++++++++++-------- tests/SapRfcConfigATest.php | 83 ------------- tests/SapRfcConfigBTest.php | 79 ------------- tests/SapRfcConnectionTest.php | 85 ++------------ tests/SapRfcTestCaseTrait.php | 24 ++-- 10 files changed, 211 insertions(+), 467 deletions(-) delete mode 100644 src/SapRfcConfigA.php delete mode 100644 src/SapRfcConfigB.php delete mode 100644 src/SapRfcConfigTrait.php delete mode 100644 tests/SapRfcConfigATest.php delete mode 100644 tests/SapRfcConfigBTest.php diff --git a/composer.json b/composer.json index 1090b84..b253972 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "require-dev": { "ext-json": "*", "phpunit/phpunit": "^4.8", - "php-sap/integration-tests": "dev-php5" + "php-sap/integration-tests": "dev-php5-v3" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 3d9108d..d5a2ab2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "244bc31803b2dc3c23c68baa9d4e7b76", + "content-hash": "21706921e3804b557ef1622462154f11", "packages": [ { "name": "php-sap/common", @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "7f331e9b2cb02591ac27ed17353109b18b9adcb9" + "reference": "6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/7f331e9b2cb02591ac27ed17353109b18b9adcb9", - "reference": "7f331e9b2cb02591ac27ed17353109b18b9adcb9", + "url": "https://api.github.com/repos/php-sap/common/zipball/6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf", + "reference": "6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf", "shasum": "" }, "require": { @@ -54,7 +54,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-11-07T16:06:35+00:00" + "time": "2019-11-26T12:24:25+00:00" }, { "name": "php-sap/datetime", @@ -112,12 +112,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "c885680649baf9e5769842302235c6e0df8a9ba7" + "reference": "16331f9d2f067d69def09a6893eb29af0e60e17b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/c885680649baf9e5769842302235c6e0df8a9ba7", - "reference": "c885680649baf9e5769842302235c6e0df8a9ba7", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/16331f9d2f067d69def09a6893eb29af0e60e17b", + "reference": "16331f9d2f067d69def09a6893eb29af0e60e17b", "shasum": "" }, "require": { @@ -151,7 +151,7 @@ "interfaces", "php-sap" ], - "time": "2019-10-30T15:27:23+00:00" + "time": "2019-11-13T17:19:53+00:00" }, { "name": "psr/container", @@ -308,16 +308,16 @@ }, { "name": "php-sap/integration-tests", - "version": "dev-php5", + "version": "dev-php5-v3", "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "85d0daf4be496a25386dcf38a2512b2a340e8cdb" + "reference": "2bfbc7d3e3ae47636311f8bfa381bc61869be150" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/85d0daf4be496a25386dcf38a2512b2a340e8cdb", - "reference": "85d0daf4be496a25386dcf38a2512b2a340e8cdb", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/2bfbc7d3e3ae47636311f8bfa381bc61869be150", + "reference": "2bfbc7d3e3ae47636311f8bfa381bc61869be150", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-11-07T15:20:35+00:00" + "time": "2019-11-28T13:16:19+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -1310,16 +1310,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.12.0", + "version": "v1.13.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -1331,7 +1331,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -1364,11 +1364,11 @@ "polyfill", "portable" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.33", + "version": "v3.4.35", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", @@ -1427,31 +1427,29 @@ }, { "name": "webmozart/assert", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -1473,7 +1471,7 @@ "check", "validate" ], - "time": "2019-08-24T08:43:50+00:00" + "time": "2019-11-24T13:36:37+00:00" } ], "aliases": [], diff --git a/src/SapRfcConfigA.php b/src/SapRfcConfigA.php deleted file mode 100644 index 0ea19b4..0000000 --- a/src/SapRfcConfigA.php +++ /dev/null @@ -1,44 +0,0 @@ - true, - 'SYSNR' => true, - 'CLIENT' => true, - 'USER' => true, - 'PASSWD' => true, - 'GWHOST' => false, - 'GWSERV' => false, - 'LANG' => false, - 'TRACE' => false - ]; - - use SapRfcConfigTrait; -} diff --git a/src/SapRfcConfigB.php b/src/SapRfcConfigB.php deleted file mode 100644 index 3ecbf54..0000000 --- a/src/SapRfcConfigB.php +++ /dev/null @@ -1,43 +0,0 @@ - true, - 'USER' => true, - 'PASSWD' => true, - 'MSHOST' => true, - 'R3NAME' => false, - 'GROUP' => false, - 'LANG' => false, - 'TRACE' => false - ]; - - use SapRfcConfigTrait; -} diff --git a/src/SapRfcConfigTrait.php b/src/SapRfcConfigTrait.php deleted file mode 100644 index 81cce35..0000000 --- a/src/SapRfcConfigTrait.php +++ /dev/null @@ -1,49 +0,0 @@ - $mandatory) { - $keyLower = strtolower($key); - if ($this->has($keyLower)) { - $method = sprintf('get%s', ucfirst($keyLower)); - $config[$key] = $this->{$method}(); - } elseif ($mandatory === true) { - throw new IncompleteConfigException(sprintf( - 'Missing mandatory key %s.', - $keyLower - )); - } - } - return $config; - } -} diff --git a/src/SapRfcConnection.php b/src/SapRfcConnection.php index 9f87878..9ead0af 100644 --- a/src/SapRfcConnection.php +++ b/src/SapRfcConnection.php @@ -1,26 +1,22 @@ createFunctionInstance('RFC_PING'); - try { - $ping->invoke(); - } catch (FunctionCallException $fcex) { - return false; + return new SapRfcFunction($this->getConnection(), $name); + } + + /** + * Open a connection in case it hasn't been done yet and return the + * connection resource. + * @return resource + * @throws ConnectionFailedException + * @throws IncompleteConfigException + */ + protected function getConnection() + { + /** + * Open a new connection resource. + */ + $connection = @saprfc_open($this->getModuleConfig()); + /** + * In case the connection couldn't be opened, remove the resource and + * throw an exception. + */ + if ($connection === false) { + unset($connection); + throw new ConnectionFailedException(sprintf( + 'Connection creation failed: %s', + @saprfc_error() + )); } - return true; + return $connection; } /** - * Closes the connection instance of the underlying PHP module. + * Get the connection configuration. + * @return array + * @throws IncompleteConfigException */ - public function close() + protected function getModuleConfig() { - if ($this->isConnected()) { - @saprfc_close($this->connection); - $this->connection = null; + $common = $this->getCommonConfig(); + /** + * Only type A and B configurations are supported by this module, + * its common classes and its interface. Therefore, we do not + * expect any other types here. + */ + if ($this->configuration instanceof ConfigTypeA) { + $specific = $this->getTypeAConfig(); + } else { + $specific = $this->getTypeBConfig(); } + //Once we end up here, the configuration is complete. + return array_merge($common, $specific); } /** - * Prepare a remote function call and return a function instance. - * @param string $name - * @return SapRfcFunction - * @throws ConnectionFailedException - * @throws UnknownFunctionException + * Get the common configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @return array + * @throws IncompleteConfigException */ - protected function createFunctionInstance($name) + private function getCommonConfig() { - return new SapRfcFunction($this->getConnection(), $name); + $config = $missing = []; + try { + $config['CLIENT'] = $this->configuration->getClient(); + } catch (ConfigKeyNotFoundException $exception) { + $missing[] = ConfigCommon::JSON_CLIENT; + } + try { + $config['USER'] = $this->configuration->getUser(); + } catch (ConfigKeyNotFoundException $exception) { + $missing[] = ConfigCommon::JSON_USER; + } + try { + $config['PASSWD'] = $this->configuration->getPasswd(); + } catch (ConfigKeyNotFoundException $exception) { + $missing[] = ConfigCommon::JSON_PASSWD; + } + if (!empty($missing)) { + throw new IncompleteConfigException(sprintf( + 'Configuration is missing mandatory key(s) %s!', + implode(', ', $missing) + )); + } + try { + $config['LANG'] = $this->configuration->getLang(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + try { + $config['TRACE'] = $this->configuration->getTrace(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + return $config; } /** - * Creates a connection using the underlying PHP module. - * @throws ConnectionFailedException + * Get the connection type A configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @return array + * @throws IncompleteConfigException */ - public function connect() + private function getTypeAConfig() { - if ($this->isConnected()) { - $this->close(); + $config = $missing = []; + try { + $config['ASHOST'] = $this->configuration->getAshost(); + } catch (ConfigKeyNotFoundException $exception) { + $missing[] = IConfigTypeA::JSON_ASHOST; } - $this->connection = @saprfc_open($this->config); - if ($this->connection === false) { - $this->connection = null; - throw new ConnectionFailedException(sprintf( - 'Connection %s creation failed: %s', - $this->getId(), - @saprfc_error() + try { + $config['SYSNR'] = $this->configuration->getSysnr(); + } catch (ConfigKeyNotFoundException $exception) { + $missing[] = IConfigTypeA::JSON_SYSNR; + } + if (!empty($missing)) { + throw new IncompleteConfigException(sprintf( + 'Configuration is missing mandatory key(s) %s!', + implode(', ', $missing) )); } + try { + $config['GWHOST'] = $this->configuration->getGwhost(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + try { + $config['GWSERV'] = $this->configuration->getGwserv(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + return $config; + } + + /** + * Get the connection type B configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @return array + * @throws IncompleteConfigException + */ + private function getTypeBConfig() + { + $config = []; + try { + $config['MSHOST'] = $this->configuration->getMshost(); + } catch (ConfigKeyNotFoundException $exception) { + throw new IncompleteConfigException(sprintf( + 'Configuration is missing mandatory key %s!', + IConfigTypeB::JSON_MSHOST + )); + } + try { + $config['R3NAME'] = $this->configuration->getR3name(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + try { + $config['GROUP'] = $this->configuration->getGroup(); + } catch (ConfigKeyNotFoundException $exception) { + //Do nothing, as these keys are not mandatory! + } + return $config; } } diff --git a/tests/SapRfcConfigATest.php b/tests/SapRfcConfigATest.php deleted file mode 100644 index 6a60eba..0000000 --- a/tests/SapRfcConfigATest.php +++ /dev/null @@ -1,83 +0,0 @@ - Date: Mon, 9 Dec 2019 13:32:19 +0100 Subject: [PATCH 15/27] fix typo in word resource --- tests/helper/saprfc.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/helper/saprfc.php b/tests/helper/saprfc.php index 6719bd6..df305a2 100644 --- a/tests/helper/saprfc.php +++ b/tests/helper/saprfc.php @@ -18,7 +18,7 @@ /** * Close connection resource. - * @param mixed $connection Connection ressource. + * @param mixed $connection Connection resource. */ function saprfc_close(&$connection) { @@ -58,7 +58,7 @@ function saprfc_exception($function) /** * Open connection. * @param array $config - * @return ressource + * @return resource */ function saprfc_open($config) { @@ -68,9 +68,9 @@ function saprfc_open($config) /** * Get function call resource. - * @param ressource $connection Connection ressource. + * @param resource $connection Connection resource. * @param string $name Function name. - * @return ressource + * @return resource */ function saprfc_function_discover($connection, $name) { @@ -80,7 +80,7 @@ function saprfc_function_discover($connection, $name) /** * Call SAP remote function with all set parameters. - * @param ressource $function + * @param resource $function * @return int */ function saprfc_call_and_receive($function) From d2a95ca60f27f4c71b6d0713cf2cb1c1d38a921d Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 17 Dec 2019 14:41:10 +0100 Subject: [PATCH 16/27] update to interface v2 and commons v3 --- composer.lock | 28 +- src/ApiTrait.php | 103 +++++ src/ConfigTrait.php | 116 ++++++ src/SapRfc.php | 312 +++++++++++++++ src/SapRfcConnection.php | 208 ---------- src/SapRfcFunction.php | 368 ------------------ tests/SapRfcConnectionTest.php | 64 --- ...tionTest.php => SapRfcIntegrationTest.php} | 123 +++--- ...RfcTestCaseTrait.php => TestCaseTrait.php} | 52 +-- 9 files changed, 631 insertions(+), 743 deletions(-) create mode 100644 src/ApiTrait.php create mode 100644 src/ConfigTrait.php create mode 100644 src/SapRfc.php delete mode 100644 src/SapRfcConnection.php delete mode 100644 src/SapRfcFunction.php delete mode 100644 tests/SapRfcConnectionTest.php rename tests/{SapRfcFunctionTest.php => SapRfcIntegrationTest.php} (80%) rename tests/{SapRfcTestCaseTrait.php => TestCaseTrait.php} (53%) diff --git a/composer.lock b/composer.lock index d5a2ab2..42e561d 100644 --- a/composer.lock +++ b/composer.lock @@ -12,12 +12,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf" + "reference": "8f02d67bc3d7cd65b78f92d1288faac751601e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf", - "reference": "6fd26e6fe1ffcfadd7b068125ead9ca3be02cbcf", + "url": "https://api.github.com/repos/php-sap/common/zipball/8f02d67bc3d7cd65b78f92d1288faac751601e08", + "reference": "8f02d67bc3d7cd65b78f92d1288faac751601e08", "shasum": "" }, "require": { @@ -54,7 +54,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-11-26T12:24:25+00:00" + "time": "2019-12-17T12:29:11+00:00" }, { "name": "php-sap/datetime", @@ -112,12 +112,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "16331f9d2f067d69def09a6893eb29af0e60e17b" + "reference": "d04c5135cc73c4ed239d232483c444a3ea430502" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/16331f9d2f067d69def09a6893eb29af0e60e17b", - "reference": "16331f9d2f067d69def09a6893eb29af0e60e17b", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/d04c5135cc73c4ed239d232483c444a3ea430502", + "reference": "d04c5135cc73c4ed239d232483c444a3ea430502", "shasum": "" }, "require": { @@ -151,7 +151,7 @@ "interfaces", "php-sap" ], - "time": "2019-11-13T17:19:53+00:00" + "time": "2019-12-17T12:22:51+00:00" }, { "name": "psr/container", @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "2bfbc7d3e3ae47636311f8bfa381bc61869be150" + "reference": "ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/2bfbc7d3e3ae47636311f8bfa381bc61869be150", - "reference": "2bfbc7d3e3ae47636311f8bfa381bc61869be150", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6", + "reference": "ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-11-28T13:16:19+00:00" + "time": "2019-12-16T16:29:15+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -1310,7 +1310,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.13.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -1368,7 +1368,7 @@ }, { "name": "symfony/yaml", - "version": "v3.4.35", + "version": "v3.4.36", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", diff --git a/src/ApiTrait.php b/src/ApiTrait.php new file mode 100644 index 0000000..a417391 --- /dev/null +++ b/src/ApiTrait.php @@ -0,0 +1,103 @@ +createMembers($def)); + } + if ($def[0]['name'] !== '') { + return new Struct($name, $direction, $optional, $this->createMembers($def)); + } + return new Value($this->abapToType($def[0]['abap']), $name, $direction, $optional); + } + + /** + * Create either struct or table members from the def array of the remote function API. + * @param array $members + * @return Element[] An array of IElement compatible objects. + * @throws SapLogicException In case a datatype is missing in the mappings array. + */ + private function createMembers($members) + { + $result = []; + foreach ($members as $member) { + $result[] = new Element($this->abapToType($member['abap']), $member['name']); + } + return $result; + } + + /** + * Convert SAPRFC abap datatype to PHP-SAP datatype. + * @param string $type The ABAP data type from the API definition. + * @return string The PHP/SAP internal data type. + * @throws SapLogicException In case a datatype is missing in the mappings array. + */ + private function abapToType($type) + { + static $mapping = [ + 'b' => Element::TYPE_INTEGER, //1-byte integer (internal) + 's' => Element::TYPE_INTEGER, //2-byte integer (internal) + 'I' => Element::TYPE_INTEGER, //4-byte integer + 'INT8' => Element::TYPE_INTEGER, //8-byte integer + 'P' => Element::TYPE_FLOAT, //packed number 1-16 bytes + 'DECFLOAT16' => Element::TYPE_FLOAT, //floating point with 16 positions + 'DECFLOAT34' => Element::TYPE_FLOAT, //floating point with 34 positions + 'F' => Element::TYPE_FLOAT, //binary floating point with 17 positions + 'C' => Element::TYPE_STRING, //fixed length text field + 'N' => Element::TYPE_INTEGER, //fixed length numeric text field 1-262143 positions + 'STRING' => Element::TYPE_STRING, //text string + 'X' => Element::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data + 'XSTRING' => Element::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data + 'D' => Element::TYPE_DATE, //date field + 'T' => Element::TYPE_TIME, //time field + ]; + if (!array_key_exists($type, $mapping)) { + throw new SapLogicException(sprintf('Unknown SAP data type \'%s\'!', $type)); + } + return $mapping[$type]; + } + + /** + * Convert SAPRFC type to PHP/SAP direction. + * @param string $type The remote function parameter type indicating whether it's an input or a return parameter. + * @return string The PHP/SAP internal direction. + * @throws SapLogicException In case the given SAP RFC type is missing in the static mapping. + */ + private function typeToDirection($type) + { + static $mapping = [ + 'IMPORT' => Value::DIRECTION_INPUT, //SAP remote function input parameter + 'EXPORT' => Value::DIRECTION_OUTPUT, //SAP remote function return value or struct + 'TABLE' => Table::DIRECTION_TABLE //SAP remote function return table + ]; + if (!array_key_exists($type, $mapping)) { + throw new SapLogicException(sprintf('Unknown SAPRFC type \'%s\'!', $type)); + } + return $mapping[$type]; + } +} diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php new file mode 100644 index 0000000..bd32192 --- /dev/null +++ b/src/ConfigTrait.php @@ -0,0 +1,116 @@ +getCommonConfig($config); + /** + * Only type A and B configurations are supported by this module, + * its common classes and its interface. Therefore, we do not + * expect any other types here. + */ + if ($config instanceof IConfigTypeA) { + $specific = $this->getTypeAConfig($config); + } else { + $specific = $this->getTypeBConfig($config); + } + //Once we end up here, the configuration is complete. + return array_merge($common, $specific); + } + + /** + * Get the common configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @param IConfigCommon $config + * @return array + * @throws IIncompleteConfigException + */ + private function getCommonConfig(IConfigCommon $config) + { + $common = []; + if ($config->getLang() !== null) { + $common['LANG'] = $config->getLang(); + } + if ($config->getTrace() !== null) { + $common['TRACE'] = $config->getTrace(); + } + $common['CLIENT'] = $config->getClient(); + $common['USER'] = $config->getUser(); + $common['PASSWD'] = $config->getPasswd(); + return $common; + } + + /** + * Get the connection type A configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @param IConfigTypeA $config + * @return array + * @throws IIncompleteConfigException + */ + private function getTypeAConfig(IConfigTypeA $config) + { + $typeA = []; + if ($config->getGwhost() !== null) { + $typeA['GWHOST'] = $config->getGwhost(); + } + if ($config->getGwserv() !== null) { + $typeA['GWSERV'] = $config->getGwserv(); + } + $typeA['ASHOST'] = $config->getAshost(); + $typeA['SYSNR'] = $config->getSysnr(); + return $typeA; + } + + /** + * Get the connection type B configuration for the saprfc module. + * + * I chose a "stupid" (and repetitive) way because it is more readable + * and thus better maintainable for others than an "intelligent" way. + * + * @param IConfigTypeB $config + * @return array + * @throws IIncompleteConfigException + */ + private function getTypeBConfig(IConfigTypeB $config) + { + $typeB = []; + if ($config->getR3name() !== null) { + $typeB['R3NAME'] = $config->getR3name(); + } + if ($config->getGroup() !== null) { + $typeB['GROUP'] = $config->getGroup(); + } + $typeB['MSHOST'] = $config->getMshost(); + return $typeB; + } +} diff --git a/src/SapRfc.php b/src/SapRfc.php new file mode 100644 index 0000000..92040b7 --- /dev/null +++ b/src/SapRfc.php @@ -0,0 +1,312 @@ +function === null) { + /** + * Create a new function resource. + */ + $this->function = @saprfc_function_discover( + $this->getConnection(), + $this->getName() + ); + if ($this->function === false) { + $this->function = null; + throw new UnknownFunctionException(sprintf( + 'Unknown function %s: %s', + $this->getName(), + @saprfc_error() + )); + } + } + return $this->function; + } + + /** + * Open a connection in case it hasn't been done yet and return the + * connection resource. + * @return resource + * @throws ConnectionFailedException + * @throws IncompleteConfigException + */ + protected function getConnection() + { + if ($this->connection === null) { + /** + * In case the is no configuration, throw an exception. + */ + if (($config = $this->getConfiguration()) === null) { + throw new IncompleteConfigException( + 'Configuration is missing!' + ); + } + /** + * Catch generic IIncompleteConfigException interface and throw the + * actual exception class of this repository. + */ + try { + $moduleConfig = $this->getModuleConfig($config); + } catch (IIncompleteConfigException $exception) { + throw new IncompleteConfigException($exception->getMessage()); + } + /** + * Create a new connection resource. + */ + $this->connection = @saprfc_open($moduleConfig); + /** + * In case the connection couldn't be opened, throw an exception. + */ + if ($this->connection === false) { + $this->connection = null; + throw new ConnectionFailedException(sprintf( + 'Connection creation failed: %s', + @saprfc_error() + )); + } + } + return $this->connection; + } + + /** + * Module specific destructor. + */ + public function __destruct() + { + if ($this->function !== null) { + @saprfc_function_free($this->function); + $this->function = null; + } + if ($this->connection !== null) { + @saprfc_close($this->connection); + $this->connection = null; + } + } + + /** + * Connect to the SAP remote system and retrieve the API of the SAP remote + * function. This ignores any API settings in this class. + * @return RemoteApi + * @throws ConnectionFailedException + * @throws IncompleteConfigException + * @throws UnknownFunctionException + * @throws SapLogicException + */ + public function extractApi() + { + $api = new RemoteApi(); + foreach ($this->saprfcFunctionInterface() as $element) { + $api->add($this->createApiValue( + strtoupper($element['name']), + $this->typeToDirection($element['type']), + (bool)$element['optional'], + $element['def'] + )); + } + return $api; + } + + /** + * Get remote function call API definition. + * @return array The array describing the remote function call API. + * @throws ConnectionFailedException + * @throws IncompleteConfigException + * @throws UnknownFunctionException + */ + protected function saprfcFunctionInterface() + { + $definitions = @saprfc_function_interface($this->getFunction()); + if ($definitions === false) { + throw new ConnectionFailedException( + 'Cannot query remote function API!' + ); + } + return $definitions; + } + + /** + * Invoke the SAP remote function call with all parameters. + * Attention: A configuration is necessary to invoke a SAP remote function + * call! + * @return array + * @throws ArrayElementMissingException + * @throws ConnectionFailedException + * @throws FunctionCallException + * @throws IncompleteConfigException + * @throws UnknownFunctionException + */ + public function invoke() + { + $this->setSapRfcInputValues($this->getApi()->getInputValues(), $this->getParams()); + $this->setSapRfcTables($this->getApi()->getTables(), $this->getParams()); + $result = @saprfc_call_and_receive($this->getFunction()); + if ($result !== 0) { + throw new FunctionCallException(sprintf( + 'Function call %s failed: %s', + $this->getName(), + @saprfc_exception($this->getFunction()) + )); + } + return $this->getSaprfcResults(); + } + + /** + * Set all input values. + * @param array $inputs The array of input parameters to set. + * @param array $params + * @return void + * @throws ConnectionFailedException + * @throws FunctionCallException + * @throws IncompleteConfigException + * @throws UnknownFunctionException + */ + private function setSapRfcInputValues($inputs, $params) + { + foreach ($inputs as $input) { + $key = $input->getName(); + if (array_key_exists($key, $params)) { + $value = $params[$key]; + if (!@saprfc_import($this->getFunction(), $key, $value)) { + throw new FunctionCallException(sprintf( + 'Function call %s failed: Assigning param %s failed. Expected type %s, actual type %s.', + $this->getName(), + $key, + $input->getType(), + gettype($value) + )); + } + } elseif (!$input->isOptional()) { + throw new FunctionCallException(sprintf( + 'Missing parameter \'%s\' for function call \'%s\'!', + $key, + $this->getName() + )); + } + } + } + + /** + * Initializes the table parameters of the remote function call. + * @param array $tables The array of table parameters to initialize. + * @param array $params + * @return void + * @throws ConnectionFailedException + * @throws FunctionCallException In case the initialization fails. + * @throws IncompleteConfigException + * @throws UnknownFunctionException + */ + private function setSapRfcTables($tables, $params) + { + foreach ($tables as $table) { + $key = $table->getName(); + /** + * Initialize each table. + */ + if (!@saprfc_table_init($this->getFunction(), $key)) { + throw new FunctionCallException(sprintf( + 'Initializing table %s for function %s failed!', + $key, + $this->getName() + )); + } + /** + * Fill the prepared table in case there are values in the parameters. + */ + if (array_key_exists($key, $params) + && is_array($params[$key]) + && count($params[$key]) > 0 + ) { + foreach ($params[$key] as $number => $row) { + if (!@saprfc_table_append($this->getFunction(), $key, $row)) { + throw new FunctionCallException(sprintf( + 'Adding row #%u to table %s for function %s failed!', + $number, + $key, + $this->getName() + )); + } + } + } + } + } + + /** + * Import results from the function call. + * @return array + * @throws ConnectionFailedException + * @throws IncompleteConfigException + * @throws UnknownFunctionException + * @throws ArrayElementMissingException + */ + private function getSaprfcResults() + { + $result = []; + foreach ($this->getApi()->getOutputValues() as $output) { + $key = $output->getName(); + $value = @saprfc_export($this->getFunction(), $key); + $result[$key] = $output->cast($value); + unset($key, $value); + } + foreach ($this->getApi()->getTables() as $table) { + $key = $table->getName(); + $rows = []; + $max = @saprfc_table_rows($this->getFunction(), $key); + for ($index = 1; $index <= $max; $index++) { + $rows[] = @saprfc_table_read($this->getFunction(), $key, $index); + } + $result[$key] = $table->cast($rows); + unset($key, $rows, $max, $index); + } + return $result; + } +} diff --git a/src/SapRfcConnection.php b/src/SapRfcConnection.php deleted file mode 100644 index 9ead0af..0000000 --- a/src/SapRfcConnection.php +++ /dev/null @@ -1,208 +0,0 @@ -getConnection(), $name); - } - - /** - * Open a connection in case it hasn't been done yet and return the - * connection resource. - * @return resource - * @throws ConnectionFailedException - * @throws IncompleteConfigException - */ - protected function getConnection() - { - /** - * Open a new connection resource. - */ - $connection = @saprfc_open($this->getModuleConfig()); - /** - * In case the connection couldn't be opened, remove the resource and - * throw an exception. - */ - if ($connection === false) { - unset($connection); - throw new ConnectionFailedException(sprintf( - 'Connection creation failed: %s', - @saprfc_error() - )); - } - return $connection; - } - - /** - * Get the connection configuration. - * @return array - * @throws IncompleteConfigException - */ - protected function getModuleConfig() - { - $common = $this->getCommonConfig(); - /** - * Only type A and B configurations are supported by this module, - * its common classes and its interface. Therefore, we do not - * expect any other types here. - */ - if ($this->configuration instanceof ConfigTypeA) { - $specific = $this->getTypeAConfig(); - } else { - $specific = $this->getTypeBConfig(); - } - //Once we end up here, the configuration is complete. - return array_merge($common, $specific); - } - - /** - * Get the common configuration for the saprfc module. - * - * I chose a "stupid" (and repetitive) way because it is more readable - * and thus better maintainable for others than an "intelligent" way. - * - * @return array - * @throws IncompleteConfigException - */ - private function getCommonConfig() - { - $config = $missing = []; - try { - $config['CLIENT'] = $this->configuration->getClient(); - } catch (ConfigKeyNotFoundException $exception) { - $missing[] = ConfigCommon::JSON_CLIENT; - } - try { - $config['USER'] = $this->configuration->getUser(); - } catch (ConfigKeyNotFoundException $exception) { - $missing[] = ConfigCommon::JSON_USER; - } - try { - $config['PASSWD'] = $this->configuration->getPasswd(); - } catch (ConfigKeyNotFoundException $exception) { - $missing[] = ConfigCommon::JSON_PASSWD; - } - if (!empty($missing)) { - throw new IncompleteConfigException(sprintf( - 'Configuration is missing mandatory key(s) %s!', - implode(', ', $missing) - )); - } - try { - $config['LANG'] = $this->configuration->getLang(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - try { - $config['TRACE'] = $this->configuration->getTrace(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - return $config; - } - - /** - * Get the connection type A configuration for the saprfc module. - * - * I chose a "stupid" (and repetitive) way because it is more readable - * and thus better maintainable for others than an "intelligent" way. - * - * @return array - * @throws IncompleteConfigException - */ - private function getTypeAConfig() - { - $config = $missing = []; - try { - $config['ASHOST'] = $this->configuration->getAshost(); - } catch (ConfigKeyNotFoundException $exception) { - $missing[] = IConfigTypeA::JSON_ASHOST; - } - try { - $config['SYSNR'] = $this->configuration->getSysnr(); - } catch (ConfigKeyNotFoundException $exception) { - $missing[] = IConfigTypeA::JSON_SYSNR; - } - if (!empty($missing)) { - throw new IncompleteConfigException(sprintf( - 'Configuration is missing mandatory key(s) %s!', - implode(', ', $missing) - )); - } - try { - $config['GWHOST'] = $this->configuration->getGwhost(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - try { - $config['GWSERV'] = $this->configuration->getGwserv(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - return $config; - } - - /** - * Get the connection type B configuration for the saprfc module. - * - * I chose a "stupid" (and repetitive) way because it is more readable - * and thus better maintainable for others than an "intelligent" way. - * - * @return array - * @throws IncompleteConfigException - */ - private function getTypeBConfig() - { - $config = []; - try { - $config['MSHOST'] = $this->configuration->getMshost(); - } catch (ConfigKeyNotFoundException $exception) { - throw new IncompleteConfigException(sprintf( - 'Configuration is missing mandatory key %s!', - IConfigTypeB::JSON_MSHOST - )); - } - try { - $config['R3NAME'] = $this->configuration->getR3name(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - try { - $config['GROUP'] = $this->configuration->getGroup(); - } catch (ConfigKeyNotFoundException $exception) { - //Do nothing, as these keys are not mandatory! - } - return $config; - } -} diff --git a/src/SapRfcFunction.php b/src/SapRfcFunction.php deleted file mode 100644 index 44f6262..0000000 --- a/src/SapRfcFunction.php +++ /dev/null @@ -1,368 +0,0 @@ -setSaprfcParameters(); - $result = @saprfc_call_and_receive($this->function); - if ($result !== 0) { - throw new FunctionCallException(sprintf( - 'Function call %s failed: %s', - $this->getName(), - @saprfc_exception($this->function) - )); - } - return $this->getSaprfcResults(); - } - - /** - * Close remote function call and clear its interface. - */ - public function __destruct() - { - if ($this->function !== null) { - @saprfc_function_free($this->function); - $this->function = null; - } - } - - /** - * Set function call parameter. - * All parameter names will be converted to upper case. - * @param string $name - * @param array|string|float|int|bool|null $value - * @return IFunction $this - * @throws InvalidArgumentException - */ - public function setParam($name, $value) - { - return parent::setParam( - strtoupper($name), - $value - ); - } - - /** - * Create a remote function call resource. - * @return mixed - * @throws UnknownFunctionException - */ - protected function getFunction() - { - $function = @saprfc_function_discover($this->connection, $this->getName()); - if ($function === false) { - $function = null; - throw new UnknownFunctionException(sprintf( - 'Unknown function %s: %s', - $this->getName(), - @saprfc_error() - )); - } - return $function; - } - - /** - * Export all function call parameters. - * @return void - * @throws FunctionCallException - */ - private function setSaprfcParameters() - { - $this->setSapRfcInputValues($this->getApi()->getInputValues()); - $this->setSapRfcTables($this->getApi()->getTables()); - } - - /** - * Set all input values. - * @param array $inputs The array of input parameters to set. - * @return void - * @throws FunctionCallException - */ - private function setSapRfcInputValues($inputs) - { - foreach ($inputs as $input) { - $name = $input->getName(); - $value = $this->getParam($name); - if (!$this->setSapRfcInputValue($name, $value, $input->isOptional())) { - throw new FunctionCallException(sprintf( - 'Function call %s failed: Assigning param %s, expected type %s, actual type %s failed.', - $this->getName(), - $name, - $input->getType(), - gettype($value) - )); - } - } - } - - /** - * Set a single input parameter value for the function call. - * @param string $name The name of the parameter. - * @param mixed $value The value of the parameter. - * @param bool $isOptional Is the parameter optional (TRUE) or mandatory (FALSE)? - * @return bool Has the parameter been set successfully? - * @throws FunctionCallException in case the parameter value is null but mandatory. - */ - private function setSapRfcInputValue($name, $value, $isOptional) - { - if ($value === null && !$isOptional) { - throw new FunctionCallException(sprintf( - 'Missing parameter \'%s\' for function call \'%s\'!', - $name, - $this->getName() - )); - } - if ($value === null) { - return true; - } - return @saprfc_import($this->function, $name, $value); - } - - /** - * Initializes the table parameters of the remote function call. - * @param array $tables The array of table parameters to initialize. - * @return void - * @throws FunctionCallException In case the initialization fails. - */ - private function setSapRfcTables($tables) - { - foreach ($tables as $table) { - $name = $table->getName(); - $result = $this->setSapRfcTable($name, $this->getParam($name)); - if ($result !== true) { - throw new FunctionCallException(sprintf( - 'Initializing table %s for function %s failed!', - $name, - $this->getName() - )); - } - } - } - - /** - * Initialize a remote function call table and add rows, in case there are rows. - * @param string $name The table name to initialize and fill. - * @param array $rows The rows to add to the table. - * @return bool Init success? - * @throws FunctionCallException - */ - private function setSapRfcTable($name, $rows) - { - if (!@saprfc_table_init($this->function, $name)) { - return false; - } - if (!is_array($rows)) { - return true; - } - foreach ($rows as $number => $row) { - if (!@saprfc_table_append($this->function, $name, $row)) { - throw new FunctionCallException(sprintf( - 'Adding row #%u to table %s for function %s failed!', - $number, - $name, - $this->getName() - )); - } - } - return true; - } - - /** - * Import results from the function call. - * @return array - */ - private function getSaprfcResults() - { - $result = []; - foreach ($this->getApi()->getOutputValues() as $output) { - $name = $output->getName(); - $value = @saprfc_export($this->function, $name); - $result[$name] = $output->cast($value); - unset($name, $value); - } - foreach ($this->getApi()->getTables() as $table) { - $name = $table->getName(); - $rows = []; - $max = @saprfc_table_rows($this->function, $name); - for ($index = 1; $index <= $max; $index++) { - $rows[] = @saprfc_table_read($this->function, $name, $index); - } - $result[$name] = $table->cast($rows); - unset($name, $rows, $max, $index); - } - return $result; - } - - /** - * Extract the remote function API and return an API description class. - * @return RemoteApi The remote API description class. - * @throws InvalidArgumentException - * @throws LogicException In case the given SAP RFC type is missing in the static mapping. - * @throws SapException In case of a general error where the remote function API cannot be queried. - */ - public function extractApi() - { - $api = new RemoteApi(); - foreach ($this->saprfcFunctionInterface() as $element) { - $api->add($this->createApiValue( - strtoupper($element['name']), - $this->typeToDirection($element['type']), - (bool)$element['optional'], - $element['def'] - )); - } - return $api; - } - - /** - * Get remote function call API definition. - * @return array The array describing the remote function call API. - * @throws SapException In case of a general error where the remote function API cannot be queried. - */ - public function saprfcFunctionInterface() - { - $definitions = @saprfc_function_interface($this->function); - if ($definitions === false) { - throw new SapException('Cannot query remote function API!'); - } - return $definitions; - } - - /** - * Create either Value, Struct or Table from a given remote function parameter or return value. - * @param string $name The name of the parameter or return value. - * @param string $direction The direction indicating whether it's a parameter or return value. - * @param bool $optional The flag, whether this parameter or return value is required. - * @param array $def The parameter or return value definition containing the data type. - * @return Value|Struct|Table - * @throws LogicException In case a datatype is missing in the mappings array. - */ - private function createApiValue($name, $direction, $optional, $def) - { - if ($direction === IArray::DIRECTION_TABLE) { - return new Table($name, $optional, $this->createMembers($def)); - } - if ($def[0]['name'] !== '') { - return new Struct($name, $direction, $optional, $this->createMembers($def)); - } - return new Value($this->abapToType($def[0]['abap']), $name, $direction, $optional); - } - - /** - * Create either struct or table members from the def array of the remote function API. - * @param array $members - * @return Element[] An array of IElement compatible objects. - * @throws LogicException In case a datatype is missing in the mappings array. - */ - private function createMembers($members) - { - $result = []; - foreach ($members as $member) { - $result[] = new Element($this->abapToType($member['abap']), $member['name']); - } - return $result; - } - - /** - * Convert SAPRFC abap datatype to PHP-SAP datatype. - * @param string $type The ABAP data type from the API definition. - * @return string The PHP/SAP internal data type. - * @throws LogicException In case a datatype is missing in the mappings array. - */ - private function abapToType($type) - { - static $mapping = [ - 'b' => IElement::TYPE_INTEGER, //1-byte integer (internal) - 's' => IElement::TYPE_INTEGER, //2-byte integer (internal) - 'I' => IElement::TYPE_INTEGER, //4-byte integer - 'INT8' => IElement::TYPE_INTEGER, //8-byte integer - 'P' => IElement::TYPE_FLOAT, //packed number 1-16 bytes - 'DECFLOAT16' => IElement::TYPE_FLOAT, //floating point with 16 positions - 'DECFLOAT34' => IElement::TYPE_FLOAT, //floating point with 34 positions - 'F' => IElement::TYPE_FLOAT, //binary floating point with 17 positions - 'C' => IElement::TYPE_STRING, //fixed length text field - 'N' => IElement::TYPE_INTEGER, //fixed length numeric text field 1-262143 positions - 'STRING' => IElement::TYPE_STRING, //text string - 'X' => IElement::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data - 'XSTRING' => IElement::TYPE_HEXBIN, //fixed length hexadecimal encoded binary data - 'D' => IElement::TYPE_DATE, //date field - 'T' => IElement::TYPE_TIME, //time field - ]; - if (!array_key_exists($type, $mapping)) { - throw new LogicException(sprintf('Unknown SAP data type \'%s\'!', $type)); - } - return $mapping[$type]; - } - - /** - * Convert SAPRFC type to PHP/SAP direction. - * @param string $type The remote function parameter type indicating whether it's an input or a return parameter. - * @return string The PHP/SAP internal direction. - * @throws LogicException In case the given SAP RFC type is missing in the static mapping. - */ - private function typeToDirection($type) - { - static $mapping = [ - 'IMPORT' => IValue::DIRECTION_INPUT, //SAP remote function input parameter - 'EXPORT' => IValue::DIRECTION_OUTPUT, //SAP remote function return value or struct - 'TABLE' => IArray::DIRECTION_TABLE //SAP remote function return table - ]; - if (!array_key_exists($type, $mapping)) { - throw new LogicException(sprintf('Unknown SAPRFC type \'%s\'!', $type)); - } - return $mapping[$type]; - } -} diff --git a/tests/SapRfcConnectionTest.php b/tests/SapRfcConnectionTest.php deleted file mode 100644 index b1587df..0000000 --- a/tests/SapRfcConnectionTest.php +++ /dev/null @@ -1,64 +0,0 @@ - 'TEST_OUT', @@ -395,40 +391,49 @@ class SapRfcFunctionTest extends AbstractFunctionTestCase ]; /** - * Implements methods of phpsap\IntegrationTests\AbstractTestCase + * @inheritDoc */ - use SapRfcTestCaseTrait; + protected function mockConnectionFailed() + { + static::mock('saprfc_open', static function ($config) { + unset($config); + return false; + }); + static::mock('saprfc_error', static function () { + return 'my error message'; + }); + } /** - * Mock the SAP RFC module for a successful SAP remote function call. + * @inheritDoc */ - protected function mockSuccessfulFunctionCall() + protected function mockSuccessfulRfcPing() { - static::mock('saprfc_open', function ($config) { + static::mock('saprfc_open', static function ($config) { if (is_array($config)) { return 'SAPRFC CONNECTION'; } return false; }); - static::mock('saprfc_close', function (&$connection) { + static::mock('saprfc_close', static function (&$connection) { $connection = null; }); - static::mock('saprfc_function_discover', function ($connection, $name) { + static::mock('saprfc_function_discover', static function ($connection, $name) { if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_PING') { return 'SAPRFC PING'; } return false; }); - static::mock('saprfc_call_and_receive', function ($function) { + static::mock('saprfc_call_and_receive', static function ($function) { if ($function === 'SAPRFC PING') { return 0; } return 1; }); - static::mock('saprfc_function_free', function (&$function) { + static::mock('saprfc_function_free', static function (&$function) { $function = null; }); - static::mock('saprfc_function_interface', function ($function) { + static::mock('saprfc_function_interface', static function ($function) { if ($function === 'SAPRFC PING') { return []; } @@ -437,91 +442,90 @@ protected function mockSuccessfulFunctionCall() } /** - * Mock the SAP RFC module for an unknown function call exception. + * @inheritDoc */ protected function mockUnknownFunctionException() { - static::mock('saprfc_open', function ($config) { + static::mock('saprfc_open', static function ($config) { if (is_array($config)) { return 'SAPRFC CONNECTION'; } return false; }); - static::mock('saprfc_close', function (&$connection) { + static::mock('saprfc_close', static function (&$connection) { $connection = null; }); - static::mock('saprfc_function_discover', function ($connection, $name) { + static::mock('saprfc_function_discover', static function ($connection, $name) { if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_PINGG') { return false; } return $name; }); - static::mock('saprfc_error', function () { + static::mock('saprfc_error', static function () { return 'function RFC_PINGG not found'; }); - static::mock('saprfc_function_free', function (&$function) { + static::mock('saprfc_function_free', static function (&$function) { $function = null; }); } /** - * Mock the SAP RFC module for a successful SAP remote function call with - * parameters and results. + * @inheritDoc */ protected function mockRemoteFunctionCallWithParametersAndResults() { - static::mock('saprfc_open', function ($config) { + static::mock('saprfc_open', static function ($config) { if (is_array($config)) { return 'SAPRFC CONNECTION'; } return false; }); - static::mock('saprfc_close', function (&$connection) { + static::mock('saprfc_close', static function (&$connection) { $connection = null; }); - static::mock('saprfc_function_discover', function ($connection, $name) { + static::mock('saprfc_function_discover', static function ($connection, $name) { if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_WALK_THRU_TEST') { return 'SAPRFC RFC_WALK_THRU_TEST'; } return false; }); - static::mock('saprfc_function_interface', function ($function) { + static::mock('saprfc_function_interface', static function ($function) { if ($function === 'SAPRFC RFC_WALK_THRU_TEST') { return static::$rfcWalkThruTestApi; } return false; }); - static::mock('saprfc_call_and_receive', function ($function) { + static::mock('saprfc_call_and_receive', static function ($function) { if ($function === 'SAPRFC RFC_WALK_THRU_TEST') { return 0; } return 1; }); - static::mock('saprfc_import', function ($function, $name, $param) { + static::mock('saprfc_import', static function ($function, $name, $param) { return ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'TEST_IN' && is_array($param) ); }); - static::mock('saprfc_table_init', function ($function, $name) { + static::mock('saprfc_table_init', static function ($function, $name) { return ($function === 'SAPRFC RFC_WALK_THRU_TEST' && in_array($name, ['LOG', 'DESTINATIONS']) ); }); - static::mock('saprfc_table_append', function ($function, $name, $param) { + static::mock('saprfc_table_append', static function ($function, $name, $param) { return ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'DESTINATIONS' && is_array($param) ); }); - static::mock('saprfc_table_append', function ($function, $name, $param) { + static::mock('saprfc_table_append', static function ($function, $name, $param) { return ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'DESTINATIONS' && is_array($param) && $param === ['RFCDEST' => 'AOP3'] ); }); - static::mock('saprfc_table_rows', function ($function, $name) { + static::mock('saprfc_table_rows', static function ($function, $name) { if ($function !== 'SAPRFC RFC_WALK_THRU_TEST') { return false; } @@ -534,7 +538,7 @@ protected function mockRemoteFunctionCallWithParametersAndResults() return false; } }); - static::mock('saprfc_table_read', function ($function, $name, $param) { + static::mock('saprfc_table_read', static function ($function, $name, $param) { if ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'LOG' && $param === 1) { return [ 'RFCDEST' => 'AOP3', @@ -544,7 +548,7 @@ protected function mockRemoteFunctionCallWithParametersAndResults() } return false; }); - static::mock('saprfc_export', function ($function, $name) { + static::mock('saprfc_export', static function ($function, $name) { if ($function === 'SAPRFC RFC_WALK_THRU_TEST' && $name === 'TEST_OUT') { return [ 'RFCFLOAT' => 70.11, @@ -563,50 +567,61 @@ protected function mockRemoteFunctionCallWithParametersAndResults() } return false; }); - static::mock('saprfc_function_free', function (&$function) { + static::mock('saprfc_function_free', static function (&$function) { $function = null; }); } /** - * Mock the SAP RFC module for a failed SAP remote function call with parameters. + * @inheritDoc */ protected function mockFailedRemoteFunctionCallWithParameters() { - static::mock('saprfc_open', function ($config) { + static::mock('saprfc_open', static function ($config) { if (is_array($config)) { return 'SAPRFC CONNECTION'; } return false; }); - static::mock('saprfc_close', function (&$connection) { + static::mock('saprfc_close', static function (&$connection) { $connection = null; }); - static::mock('saprfc_function_discover', function ($connection, $name) { + static::mock('saprfc_function_discover', static function ($connection, $name) { if ($connection === 'SAPRFC CONNECTION' && $name === 'RFC_READ_TABLE') { return 'SAPRFC RFC_READ_TABLE'; } return false; }); - static::mock('saprfc_function_interface', function ($function) { + static::mock('saprfc_function_interface', static function ($function) { if ($function === 'SAPRFC RFC_READ_TABLE') { return static::$rfcReadTableApi; } return false; }); - static::mock('saprfc_call_and_receive', function ($function) { + static::mock('saprfc_call_and_receive', static function ($function) { if ($function === 'SAPRFC RFC_READ_TABLE') { return 1; } - throw new \RuntimeException('Unexpected function instance.'); + throw new RuntimeException('Unexpected function instance.'); }); - static::mock('saprfc_import', function ($function, $name, $param) { + static::mock('saprfc_import', static function ($function, $name, $param) { return ($function === 'SAPRFC RFC_READ_TABLE' && $name === 'QUERY_TABLE' - && $param === '' + && $param === '&' ); }); - static::mock('saprfc_function_free', function (&$function) { + static::mock('saprfc_table_init', static function ($function, $name) { + return ($function === 'SAPRFC RFC_READ_TABLE' + && in_array($name, ['DATA', 'FIELDS', 'OPTIONS']) + ); + }); + static::mock('saprfc_exception', static function ($function) { + if ($function === 'SAPRFC RFC_READ_TABLE') { + return 'My exception message.'; + } + throw new RuntimeException('Expected RFC_READ_TABLE function!'); + }); + static::mock('saprfc_function_free', static function (&$function) { $function = null; }); } diff --git a/tests/SapRfcTestCaseTrait.php b/tests/TestCaseTrait.php similarity index 53% rename from tests/SapRfcTestCaseTrait.php rename to tests/TestCaseTrait.php index 669b07f..28b3532 100644 --- a/tests/SapRfcTestCaseTrait.php +++ b/tests/TestCaseTrait.php @@ -2,26 +2,33 @@ namespace tests\phpsap\saprfc; -use phpsap\classes\Config\ConfigTypeA; -use phpsap\interfaces\Config\IConfiguration; -use phpsap\saprfc\SapRfcConnection; +use phpsap\saprfc\SapRfc; /** - * Trait tests\phpsap\saprfc\SapRfcTestCaseTrait + * Trait TestCaseTrait * - * Implement methods of phpsap\IntegrationTests\AbstractTestCase + * Collect methods common to all test cases extending the integration tests. * * @package tests\phpsap\saprfc * @author Gregor J. * @license MIT */ -trait SapRfcTestCaseTrait +trait TestCaseTrait { + /** + * Return the name of the class, used for testing. + * @return string + */ + public static function getClassName() + { + return SapRfc::class; + } + /** * Get the name of the PHP module. * @return string */ - public function getModuleName() + public static function getModuleName() { return 'saprfc'; } @@ -30,7 +37,7 @@ public function getModuleName() * Get the path to the PHP/SAP configuration file. * @return string */ - public function getSapConfigFile() + public static function getSapConfigFile() { return __DIR__ . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'sap.json'; } @@ -39,7 +46,7 @@ public function getSapConfigFile() * Get the path to the filename containing the SAP RFC module mockups. * @return string */ - public function getModuleTemplateFile() + public static function getModuleTemplateFile() { return __DIR__ . DIRECTORY_SEPARATOR . 'helper' . DIRECTORY_SEPARATOR . 'saprfc.php'; } @@ -48,7 +55,7 @@ public function getModuleTemplateFile() * Get an array of valid SAP RFC module function or class method names. * @return array */ - public function getValidModuleFunctions() + public static function getValidModuleFunctions() { return [ 'saprfc_close', @@ -67,29 +74,4 @@ public function getValidModuleFunctions() 'saprfc_table_read' ]; } - - /** - * Create a new instance of a PHP/SAP connection class. - * @param IConfiguration|null $config The PHP/SAP configuration. Default: null - * @return SapRfcConnection - * @throws \InvalidArgumentException - */ - public function newConnection(IConfiguration $config = null) - { - if ($config === null) { - return new SapRfcConnection(new ConfigTypeA()); - } - return new SapRfcConnection($config); - } - - /** - * Clean up trace files after tests. - */ - public function __destruct() - { - $traceFile = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'dev_rfc.trc'; - if (file_exists($traceFile)) { - unlink($traceFile); - } - } } From 998419a58d80cc1ad3da7b6aee91685d2e970eeb Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 17 Dec 2019 14:47:51 +0100 Subject: [PATCH 17/27] update to latest integration test --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 42e561d..af78f9d 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6" + "reference": "332353717d3d644988c9faaaa5ca528d10dd8fc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6", - "reference": "ab5afd0ed7d1d6465a4a974dd0a466ca3bc822c6", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/332353717d3d644988c9faaaa5ca528d10dd8fc1", + "reference": "332353717d3d644988c9faaaa5ca528d10dd8fc1", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-12-16T16:29:15+00:00" + "time": "2019-12-17T13:45:38+00:00" }, { "name": "phpdocumentor/reflection-common", From 219d562b05faebfd97ad6e49c7480586b5f3d20c Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 27 Jan 2020 16:05:06 +0100 Subject: [PATCH 18/27] add code and previous exception --- src/SapRfc.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SapRfc.php b/src/SapRfc.php index 92040b7..fcfd37b 100644 --- a/src/SapRfc.php +++ b/src/SapRfc.php @@ -98,7 +98,11 @@ protected function getConnection() try { $moduleConfig = $this->getModuleConfig($config); } catch (IIncompleteConfigException $exception) { - throw new IncompleteConfigException($exception->getMessage()); + throw new IncompleteConfigException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); } /** * Create a new connection resource. From 916b721991f374b9a2048f89353729cff8942577 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 27 Jan 2020 16:43:45 +0100 Subject: [PATCH 19/27] add rfc trace file to git ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 48b8bf9..51356db 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor/ +dev_rfc.trc From 4db4ffd96a3bd8b5f4ce6b5d0faeeca02d797397 Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 28 Jan 2020 16:52:17 +0100 Subject: [PATCH 20/27] update composer --- composer.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/composer.lock b/composer.lock index af78f9d..0c29fd2 100644 --- a/composer.lock +++ b/composer.lock @@ -112,12 +112,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "d04c5135cc73c4ed239d232483c444a3ea430502" + "reference": "bc06434bfdd038264f02dacc29b924e027485995" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/d04c5135cc73c4ed239d232483c444a3ea430502", - "reference": "d04c5135cc73c4ed239d232483c444a3ea430502", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/bc06434bfdd038264f02dacc29b924e027485995", + "reference": "bc06434bfdd038264f02dacc29b924e027485995", "shasum": "" }, "require": { @@ -151,7 +151,7 @@ "interfaces", "php-sap" ], - "time": "2019-12-17T12:22:51+00:00" + "time": "2020-01-13T15:26:07+00:00" }, { "name": "psr/container", @@ -260,20 +260,20 @@ }, { "name": "kba-team/memory-container", - "version": "v1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/the-kbA-team/memory-container.git", - "reference": "38bfdbeb64d3e4cc2c0f21bc7c09e325e50f8b87" + "reference": "632355a5d69872a08022ee9b9f7fce93452a2d36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/the-kbA-team/memory-container/zipball/38bfdbeb64d3e4cc2c0f21bc7c09e325e50f8b87", - "reference": "38bfdbeb64d3e4cc2c0f21bc7c09e325e50f8b87", + "url": "https://api.github.com/repos/the-kbA-team/memory-container/zipball/632355a5d69872a08022ee9b9f7fce93452a2d36", + "reference": "632355a5d69872a08022ee9b9f7fce93452a2d36", "shasum": "" }, "require": { - "php": "^5.5|^7.0", + "php": "^5.5", "psr/container": "^1.0" }, "provide": { @@ -304,7 +304,7 @@ "in-memory", "singleton" ], - "time": "2019-01-11T11:24:37+00:00" + "time": "2020-01-27T12:19:33+00:00" }, { "name": "php-sap/integration-tests", @@ -498,33 +498,33 @@ }, { "name": "phpspec/prophecy", - "version": "1.9.0", + "version": "v1.10.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203" + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203", - "reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b4400efc9d206e83138e2bb97ed7f5b14b831cd9", + "reference": "b4400efc9d206e83138e2bb97ed7f5b14b831cd9", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -557,7 +557,7 @@ "spy", "stub" ], - "time": "2019-10-03T11:07:50+00:00" + "time": "2020-01-20T15:57:02+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1368,16 +1368,16 @@ }, { "name": "symfony/yaml", - "version": "v3.4.36", + "version": "v3.4.37", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "dab657db15207879217fc81df4f875947bf68804" + "reference": "aa46bc2233097d5212332c907f9911533acfbf80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/dab657db15207879217fc81df4f875947bf68804", - "reference": "dab657db15207879217fc81df4f875947bf68804", + "url": "https://api.github.com/repos/symfony/yaml/zipball/aa46bc2233097d5212332c907f9911533acfbf80", + "reference": "aa46bc2233097d5212332c907f9911533acfbf80", "shasum": "" }, "require": { @@ -1423,7 +1423,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-10-24T15:33:53+00:00" + "time": "2020-01-13T08:00:59+00:00" }, { "name": "webmozart/assert", From d3b22d6b9b9322bfcc9906b143fffef0db06a9e4 Mon Sep 17 00:00:00 2001 From: Gregor Date: Tue, 28 Jan 2020 16:52:25 +0100 Subject: [PATCH 21/27] psr-12 fix --- src/SapRfc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SapRfc.php b/src/SapRfc.php index fcfd37b..a9b8e72 100644 --- a/src/SapRfc.php +++ b/src/SapRfc.php @@ -266,7 +266,8 @@ private function setSapRfcTables($tables, $params) /** * Fill the prepared table in case there are values in the parameters. */ - if (array_key_exists($key, $params) + if ( + array_key_exists($key, $params) && is_array($params[$key]) && count($params[$key]) > 0 ) { From 7efff6ed92b4066c39889382c1d50af94c1ffa83 Mon Sep 17 00:00:00 2001 From: Gregor Date: Wed, 29 Jan 2020 08:47:05 +0100 Subject: [PATCH 22/27] move traits to separate subdirectory --- src/SapRfc.php | 2 ++ src/{ => Traits}/ApiTrait.php | 2 +- src/{ => Traits}/ConfigTrait.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) rename src/{ => Traits}/ApiTrait.php (99%) rename src/{ => Traits}/ConfigTrait.php (99%) diff --git a/src/SapRfc.php b/src/SapRfc.php index a9b8e72..de6abeb 100644 --- a/src/SapRfc.php +++ b/src/SapRfc.php @@ -11,6 +11,8 @@ use phpsap\exceptions\SapLogicException; use phpsap\exceptions\UnknownFunctionException; use phpsap\interfaces\exceptions\IIncompleteConfigException; +use phpsap\saprfc\Traits\ApiTrait; +use phpsap\saprfc\Traits\ConfigTrait; /** * Class phpsap\saprfc\SapRfc diff --git a/src/ApiTrait.php b/src/Traits/ApiTrait.php similarity index 99% rename from src/ApiTrait.php rename to src/Traits/ApiTrait.php index a417391..9bb8ca5 100644 --- a/src/ApiTrait.php +++ b/src/Traits/ApiTrait.php @@ -1,6 +1,6 @@ Date: Wed, 29 Jan 2020 17:56:36 +0100 Subject: [PATCH 23/27] use phpunit tearDown() to remove saprfc trace file --- tests/TestCaseTrait.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/TestCaseTrait.php b/tests/TestCaseTrait.php index 28b3532..36e0043 100644 --- a/tests/TestCaseTrait.php +++ b/tests/TestCaseTrait.php @@ -74,4 +74,16 @@ public static function getValidModuleFunctions() 'saprfc_table_read' ]; } + + /** + * Remove sapnwrfc trace file. + */ + public function tearDown() + { + $traceFile = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'dev_rfc.trc'; + if (file_exists($traceFile)) { + unlink($traceFile); + } + parent::tearDown(); + } } From 2dd441f18e11cef7da96f635b93018a182d7a59f Mon Sep 17 00:00:00 2001 From: Gregor Date: Thu, 30 Jan 2020 14:29:38 +0100 Subject: [PATCH 24/27] update integration tests in composer --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 0c29fd2..13d20c4 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "332353717d3d644988c9faaaa5ca528d10dd8fc1" + "reference": "71264004981588e3fcd80ed9030ffc0a67085f09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/332353717d3d644988c9faaaa5ca528d10dd8fc1", - "reference": "332353717d3d644988c9faaaa5ca528d10dd8fc1", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/71264004981588e3fcd80ed9030ffc0a67085f09", + "reference": "71264004981588e3fcd80ed9030ffc0a67085f09", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2019-12-17T13:45:38+00:00" + "time": "2020-01-30T11:59:44+00:00" }, { "name": "phpdocumentor/reflection-common", From c79168cf3cc4f2dd474915d62dc2a1fad9228a06 Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 31 Jan 2020 15:18:51 +0100 Subject: [PATCH 25/27] update raw API returns as seen by the module --- tests/SapRfcIntegrationTest.php | 782 +++++++++++++++++--------------- 1 file changed, 426 insertions(+), 356 deletions(-) diff --git a/tests/SapRfcIntegrationTest.php b/tests/SapRfcIntegrationTest.php index a960134..eedeb00 100644 --- a/tests/SapRfcIntegrationTest.php +++ b/tests/SapRfcIntegrationTest.php @@ -20,374 +20,444 @@ class SapRfcIntegrationTest extends AbstractSapRfcTestCase { use TestCaseTrait; + /** + * @var array The raw API of RFC_WALK_THRU_TEST as seen by the module. + */ public static $rfcWalkThruTestApi = [ - [ - 'name' => 'TEST_OUT', - 'type' => 'EXPORT', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'RFCFLOAT', - 'abap' => 'F', - 'len' => 8, - 'dec' => 0, - 'offset' => 0 - ], - [ - 'name' => 'RFCCHAR1', - 'abap' => 'C', - 'len' => 1, - 'dec' => 0, - 'offset' => 8 - ], - [ - 'name' => 'RFCINT2', - 'abap' => 's', - 'len' => 2, - 'dec' => 0, - 'offset' => 10 - ], - [ - 'name' => 'RFCINT1', - 'abap' => 'b', - 'len' => 1, - 'dec' => 0, - 'offset' => 12 - ], - [ - 'name' => 'RFCCHAR4', - 'abap' => 'C', - 'len' => 4, - 'dec' => 0, - 'offset' => 13 - ], - [ - 'name' => 'RFCINT4', - 'abap' => 'I', - 'len' => 4, - 'dec' => 0, - 'offset' => 20 - ], - [ - 'name' => 'RFCHEX3', - 'abap' => 'X', - 'len' => 3, - 'dec' => 0, - 'offset' => 24 - ], - [ - 'name' => 'RFCCHAR2', - 'abap' => 'C', - 'len' => 2, - 'dec' => 0, - 'offset' => 27 - ], - [ - 'name' => 'RFCTIME', - 'abap' => 'T', - 'len' => 6, - 'dec' => 0, - 'offset' => 29 - ], - [ - 'name' => 'RFCDATE', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 35 - ], - [ - 'name' => 'RFCDATA1', - 'abap' => 'C', - 'len' => 50, - 'dec' => 0, - 'offset' => 43 - ], - [ - 'name' => 'RFCDATA2', - 'abap' => 'C', - 'len' => 50, - 'dec' => 0, - 'offset' => 93 - ] - ] - ], - [ - 'name' => 'TEST_IN', - 'type' => 'IMPORT', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'RFCFLOAT', - 'abap' => 'F', - 'len' => 8, - 'dec' => 0, - 'offset' => 0 - ], - [ - 'name' => 'RFCCHAR1', - 'abap' => 'C', - 'len' => 1, - 'dec' => 0, - 'offset' => 8 - ], - [ - 'name' => 'RFCINT2', - 'abap' => 's', - 'len' => 2, - 'dec' => 0, - 'offset' => 10 - ], - [ - 'name' => 'RFCINT1', - 'abap' => 'b', - 'len' => 1, - 'dec' => 0, - 'offset' => 12 - ], - [ - 'name' => 'RFCCHAR4', - 'abap' => 'C', - 'len' => 4, - 'dec' => 0, - 'offset' => 13 - ], - [ - 'name' => 'RFCINT4', - 'abap' => 'I', - 'len' => 4, - 'dec' => 0, - 'offset' => 20 - ], - [ - 'name' => 'RFCHEX3', - 'abap' => 'X', - 'len' => 3, - 'dec' => 0, - 'offset' => 24 - ], - [ - 'name' => 'RFCCHAR2', - 'abap' => 'C', - 'len' => 2, - 'dec' => 0, - 'offset' => 27 - ], - [ - 'name' => 'RFCTIME', - 'abap' => 'T', - 'len' => 6, - 'dec' => 0, - 'offset' => 29 - ], - [ - 'name' => 'RFCDATE', - 'abap' => 'D', - 'len' => 8, - 'dec' => 0, - 'offset' => 35 - ], - [ - 'name' => 'RFCDATA1', - 'abap' => 'C', - 'len' => 50, - 'dec' => 0, - 'offset' => 43 - ], - [ - 'name' => 'RFCDATA2', - 'abap' => 'C', - 'len' => 50, - 'dec' => 0, - 'offset' => 93 - ] - ] - ], - [ - 'name' => 'DESTINATIONS', - 'type' => 'TABLE', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'RFCDEST', - 'abap' => 'C', - 'len' => 32, - 'dec' => 0, - 'offset' => 0 - ] - ] - ], - [ - 'name' => 'LOG', - 'type' => 'TABLE', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'RFCDEST', - 'abap' => 'C', - 'len' => 32, - 'dec' => 0, - 'offset' => 0 - ], - [ - 'name' => 'RFCWHOAMI', - 'abap' => 'C', - 'len' => 32, - 'dec' => 0, - 'offset' => 32 - ], - [ - 'name' => 'RFCLOG', - 'abap' => 'C', - 'len' => 70, - 'dec' => 0, - 'offset' => 64 - ] - ] - ] + 0 => + [ + 'name' => 'TEST_OUT', + 'type' => 'EXPORT', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'RFCFLOAT', + 'abap' => 'F', + 'len' => 8, + 'dec' => 0, + 'offset' => 0, + ], + 1 => + [ + 'name' => 'RFCCHAR1', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 8, + ], + 2 => + [ + 'name' => 'RFCINT2', + 'abap' => 's', + 'len' => 2, + 'dec' => 0, + 'offset' => 10, + ], + 3 => + [ + 'name' => 'RFCINT1', + 'abap' => 'b', + 'len' => 1, + 'dec' => 0, + 'offset' => 12, + ], + 4 => + [ + 'name' => 'RFCCHAR4', + 'abap' => 'C', + 'len' => 4, + 'dec' => 0, + 'offset' => 13, + ], + 5 => + [ + 'name' => 'RFCINT4', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 20, + ], + 6 => + [ + 'name' => 'RFCHEX3', + 'abap' => 'X', + 'len' => 3, + 'dec' => 0, + 'offset' => 24, + ], + 7 => + [ + 'name' => 'RFCCHAR2', + 'abap' => 'C', + 'len' => 2, + 'dec' => 0, + 'offset' => 27, + ], + 8 => + [ + 'name' => 'RFCTIME', + 'abap' => 'T', + 'len' => 6, + 'dec' => 0, + 'offset' => 29, + ], + 9 => + [ + 'name' => 'RFCDATE', + 'abap' => 'D', + 'len' => 8, + 'dec' => 0, + 'offset' => 35, + ], + 10 => + [ + 'name' => 'RFCDATA1', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 43, + ], + 11 => + [ + 'name' => 'RFCDATA2', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 93, + ], + ], + ], + 1 => + [ + 'name' => 'TEST_IN', + 'type' => 'IMPORT', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'RFCFLOAT', + 'abap' => 'F', + 'len' => 8, + 'dec' => 0, + 'offset' => 0, + ], + 1 => + [ + 'name' => 'RFCCHAR1', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 8, + ], + 2 => + [ + 'name' => 'RFCINT2', + 'abap' => 's', + 'len' => 2, + 'dec' => 0, + 'offset' => 10, + ], + 3 => + [ + 'name' => 'RFCINT1', + 'abap' => 'b', + 'len' => 1, + 'dec' => 0, + 'offset' => 12, + ], + 4 => + [ + 'name' => 'RFCCHAR4', + 'abap' => 'C', + 'len' => 4, + 'dec' => 0, + 'offset' => 13, + ], + 5 => + [ + 'name' => 'RFCINT4', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 20, + ], + 6 => + [ + 'name' => 'RFCHEX3', + 'abap' => 'X', + 'len' => 3, + 'dec' => 0, + 'offset' => 24, + ], + 7 => + [ + 'name' => 'RFCCHAR2', + 'abap' => 'C', + 'len' => 2, + 'dec' => 0, + 'offset' => 27, + ], + 8 => + [ + 'name' => 'RFCTIME', + 'abap' => 'T', + 'len' => 6, + 'dec' => 0, + 'offset' => 29, + ], + 9 => + [ + 'name' => 'RFCDATE', + 'abap' => 'D', + 'len' => 8, + 'dec' => 0, + 'offset' => 35, + ], + 10 => + [ + 'name' => 'RFCDATA1', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 43, + ], + 11 => + [ + 'name' => 'RFCDATA2', + 'abap' => 'C', + 'len' => 50, + 'dec' => 0, + 'offset' => 93, + ], + ], + ], + 2 => + [ + 'name' => 'DESTINATIONS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'RFCDEST', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 0, + ], + ], + ], + 3 => + [ + 'name' => 'LOG', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'RFCDEST', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 0, + ], + 1 => + [ + 'name' => 'RFCWHOAMI', + 'abap' => 'C', + 'len' => 32, + 'dec' => 0, + 'offset' => 32, + ], + 2 => + [ + 'name' => 'RFCLOG', + 'abap' => 'C', + 'len' => 70, + 'dec' => 0, + 'offset' => 64, + ], + ], + ], ]; + /** + * @var array The raw API of RFC_READ_TABLE as seen by the module. + */ public static $rfcReadTableApi = [ - [ - 'name' => 'DELIMITER', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => [ - [ - 'name' => '', - 'abap' => 'C', - 'len' => 1, - 'dec' => 0, - 'offset' => 0, - ], + 0 => + [ + 'name' => 'DELIMITER', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => + [ + 0 => + [ + 'name' => '', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'NO_DATA', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => [ - [ - 'name' => '', - 'abap' => 'C', - 'len' => 1, - 'dec' => 0, - 'offset' => 0, - ], + 1 => + [ + 'name' => 'NO_DATA', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => + [ + 0 => + [ + 'name' => '', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'QUERY_TABLE', - 'type' => 'IMPORT', - 'optional' => 0, - 'def' => [ - [ - 'name' => '', - 'abap' => 'C', - 'len' => 30, - 'dec' => 0, - 'offset' => 0, - ], + 2 => + [ + 'name' => 'QUERY_TABLE', + 'type' => 'IMPORT', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => '', + 'abap' => 'C', + 'len' => 30, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'ROWCOUNT', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => [ - [ - 'name' => '', - 'abap' => 'I', - 'len' => 4, - 'dec' => 0, - 'offset' => 0, - ], + 3 => + [ + 'name' => 'ROWCOUNT', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => + [ + 0 => + [ + 'name' => '', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'ROWSKIPS', - 'type' => 'IMPORT', - 'optional' => 1, - 'def' => [ - [ - 'name' => '', - 'abap' => 'I', - 'len' => 4, - 'dec' => 0, - 'offset' => 0, - ], + 4 => + [ + 'name' => 'ROWSKIPS', + 'type' => 'IMPORT', + 'optional' => 1, + 'def' => + [ + 0 => + [ + 'name' => '', + 'abap' => 'I', + 'len' => 4, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'DATA', - 'type' => 'TABLE', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'WA', - 'abap' => 'C', - 'len' => 512, - 'dec' => 0, - 'offset' => 0, - ], + 5 => + [ + 'name' => 'DATA', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'WA', + 'abap' => 'C', + 'len' => 512, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], - [ - 'name' => 'FIELDS', - 'type' => 'TABLE', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'FIELDNAME', - 'abap' => 'C', - 'len' => 30, - 'dec' => 0, - 'offset' => 0, - ], - [ - 'name' => 'OFFSET', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 30, - ], - [ - 'name' => 'LENGTH', - 'abap' => 'N', - 'len' => 6, - 'dec' => 0, - 'offset' => 36, - ], - [ - 'name' => 'TYPE', - 'abap' => 'C', - 'len' => 1, - 'dec' => 0, - 'offset' => 42, - ], - [ - 'name' => 'FIELDTEXT', - 'abap' => 'C', - 'len' => 60, - 'dec' => 0, - 'offset' => 43, - ], + 6 => + [ + 'name' => 'FIELDS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'FIELDNAME', + 'abap' => 'C', + 'len' => 30, + 'dec' => 0, + 'offset' => 0, + ], + 1 => + [ + 'name' => 'OFFSET', + 'abap' => 'N', + 'len' => 6, + 'dec' => 0, + 'offset' => 30, + ], + 2 => + [ + 'name' => 'LENGTH', + 'abap' => 'N', + 'len' => 6, + 'dec' => 0, + 'offset' => 36, + ], + 3 => + [ + 'name' => 'TYPE', + 'abap' => 'C', + 'len' => 1, + 'dec' => 0, + 'offset' => 42, + ], + 4 => + [ + 'name' => 'FIELDTEXT', + 'abap' => 'C', + 'len' => 60, + 'dec' => 0, + 'offset' => 43, + ], + ], ], - ], - [ - 'name' => 'OPTIONS', - 'type' => 'TABLE', - 'optional' => 0, - 'def' => [ - [ - 'name' => 'TEXT', - 'abap' => 'C', - 'len' => 72, - 'dec' => 0, - 'offset' => 0, - ], + 7 => + [ + 'name' => 'OPTIONS', + 'type' => 'TABLE', + 'optional' => 0, + 'def' => + [ + 0 => + [ + 'name' => 'TEXT', + 'abap' => 'C', + 'len' => 72, + 'dec' => 0, + 'offset' => 0, + ], + ], ], - ], ]; /** From c81fdc56700d4f658b27522c48acc7de93172bce Mon Sep 17 00:00:00 2001 From: Gregor Date: Fri, 31 Jan 2020 15:41:17 +0100 Subject: [PATCH 26/27] update integration tests --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 13d20c4..b771bc1 100644 --- a/composer.lock +++ b/composer.lock @@ -312,12 +312,12 @@ "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "71264004981588e3fcd80ed9030ffc0a67085f09" + "reference": "c9874de263ae8e131f6cabaa5322ac2f0bea47bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/71264004981588e3fcd80ed9030ffc0a67085f09", - "reference": "71264004981588e3fcd80ed9030ffc0a67085f09", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/c9874de263ae8e131f6cabaa5322ac2f0bea47bf", + "reference": "c9874de263ae8e131f6cabaa5322ac2f0bea47bf", "shasum": "" }, "require": { @@ -348,7 +348,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2020-01-30T11:59:44+00:00" + "time": "2020-01-31T14:32:19+00:00" }, { "name": "phpdocumentor/reflection-common", From 89a711c2245d776b88b821639fde0122275107a9 Mon Sep 17 00:00:00 2001 From: Gregor Date: Mon, 3 Feb 2020 15:20:44 +0100 Subject: [PATCH 27/27] switch to interfaces v2 and commons v3 Updated README too. Removed sudo from travis config and added os linux. --- .travis.yml | 2 +- README.md | 46 +++++++++++----- composer.json | 10 ++-- composer.lock | 149 ++++++++++++++++++++++++-------------------------- 4 files changed, 110 insertions(+), 97 deletions(-) diff --git a/.travis.yml b/.travis.yml index 849cffc..638baf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: php -sudo: false +os: linux dist: trusty php: - 5.5 diff --git a/README.md b/README.md index e6bd74e..04209ae 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,42 @@ This repository implements the [PHP/SAP][phpsap] interface for [Eduard Kouckys l ## Usage ```sh -composer require php-sap/saprfc-koucky:^2.0 +composer require php-sap/saprfc-koucky ``` ```php 'sap.example.com', - 'sysnr' => '001', - 'client' => '002', - 'user' => 'username', - 'passwd' => 'password' -]))) - ->prepareFunction('MY_COOL_SAP_REMOTE_FUNCTION') - ->setParam('INPUT_PARAM', 'some input value') - ->invoke(); +//Include the composer autoloader ... +require_once 'vendor/autoload.php'; +//... and add the namespaces of the classes used. +use phpsap\classes\Config\ConfigTypeA; +use phpsap\DateTime\SapDateTime; +use phpsap\saprfc\SapRfc; +/** + * Create an instance of the SAP remote function using its + * name, input parameters, and connection configuration. + * + * The imaginary SAP remote function requires a + * date as input and will return a date as output. + * + * In this case the configuration array is defined manually. + */ +$result = (new SapRfc( + 'MY_COOL_SAP_REMOTE_FUNCTION', + [ + 'IV_DATE' => (new DateTime('2019-12-31')) + ->format(SapDateTime::SAP_DATE) + ], + new ConfigTypeA([ + ConfigTypeA::JSON_ASHOST => 'sap.example.com', + ConfigTypeA::JSON_SYSNR => '999', + ConfigTypeA::JSON_CLIENT => '001', + ConfigTypeA::JSON_USER => 'username', + ConfigTypeA::JSON_PASSWD => 'password' + ]) +))->invoke(); +//The output array contains a DateTime object. +echo $result['OV_DATE']->format('Y-m-d') . PHP_EOL; ``` For further documentation, please read the documentation on [PHP/SAP][phpsap]! diff --git a/composer.json b/composer.json index b253972..4d55440 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "koucky" ], "provide": { - "php-sap/interfaces": "v2.x-dev" + "php-sap/interfaces": "^2.0" }, "conflict": { "php-sap/saprfc-harding": "*", @@ -30,15 +30,15 @@ }, "minimum-stability": "stable", "require": { - "php": "~5.5.0", + "php": "^5.5", "ext-saprfc": "*", - "php-sap/interfaces": "v2.x-dev", - "php-sap/common": "v3.x-dev" + "php-sap/interfaces": "^2.0", + "php-sap/common": "^3.0" }, "require-dev": { "ext-json": "*", "phpunit/phpunit": "^4.8", - "php-sap/integration-tests": "dev-php5-v3" + "php-sap/integration-tests": "^3.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index b771bc1..23b77b3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,28 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "21706921e3804b557ef1622462154f11", + "content-hash": "d033613aa7710df557f0e60974eeaad2", "packages": [ { "name": "php-sap/common", - "version": "v3.x-dev", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/php-sap/common.git", - "reference": "8f02d67bc3d7cd65b78f92d1288faac751601e08" + "reference": "d665349aff1ebbdd4ca6e72023fcc3cf676e63e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/common/zipball/8f02d67bc3d7cd65b78f92d1288faac751601e08", - "reference": "8f02d67bc3d7cd65b78f92d1288faac751601e08", + "url": "https://api.github.com/repos/php-sap/common/zipball/d665349aff1ebbdd4ca6e72023fcc3cf676e63e3", + "reference": "d665349aff1ebbdd4ca6e72023fcc3cf676e63e3", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=5.5.0", + "php": "^5.5|^7.0", "php-sap/datetime": "^1.1", - "php-sap/interfaces": "v2.x-dev", - "psr/container": "^1.0" + "php-sap/interfaces": "^2.0" }, "require-dev": { "phpunit/phpunit": "^4.8" @@ -54,7 +53,7 @@ "PHPSAP", "php-sap" ], - "time": "2019-12-17T12:29:11+00:00" + "time": "2020-02-03T13:09:02+00:00" }, { "name": "php-sap/datetime", @@ -108,21 +107,21 @@ }, { "name": "php-sap/interfaces", - "version": "v2.x-dev", + "version": "v2.0.0", "source": { "type": "git", "url": "https://github.com/php-sap/interfaces.git", - "reference": "bc06434bfdd038264f02dacc29b924e027485995" + "reference": "11f476ce12f8fc359c148950b218d186b5c29ec2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/interfaces/zipball/bc06434bfdd038264f02dacc29b924e027485995", - "reference": "bc06434bfdd038264f02dacc29b924e027485995", + "url": "https://api.github.com/repos/php-sap/interfaces/zipball/11f476ce12f8fc359c148950b218d186b5c29ec2", + "reference": "11f476ce12f8fc359c148950b218d186b5c29ec2", "shasum": "" }, "require": { "ext-json": "*", - "php": ">=5.5.0" + "php": "^5.5|^7.0" }, "conflict": { "kba-team/php-sap": "*" @@ -151,56 +150,7 @@ "interfaces", "php-sap" ], - "time": "2020-01-13T15:26:07+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" + "time": "2020-02-03T12:48:15+00:00" } ], "packages-dev": [ @@ -308,25 +258,25 @@ }, { "name": "php-sap/integration-tests", - "version": "dev-php5-v3", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/php-sap/integration-tests.git", - "reference": "c9874de263ae8e131f6cabaa5322ac2f0bea47bf" + "reference": "13ef752ddd31c150a4c6643d939329ada5301a56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/c9874de263ae8e131f6cabaa5322ac2f0bea47bf", - "reference": "c9874de263ae8e131f6cabaa5322ac2f0bea47bf", + "url": "https://api.github.com/repos/php-sap/integration-tests/zipball/13ef752ddd31c150a4c6643d939329ada5301a56", + "reference": "13ef752ddd31c150a4c6643d939329ada5301a56", "shasum": "" }, "require": { "ext-json": "*", "kba-team/memory-container": "^1.0", "php": "^5.5", - "php-sap/common": "v3.x-dev", + "php-sap/common": "^3.0", "php-sap/datetime": "^1.1", - "php-sap/interfaces": "v2.x-dev", + "php-sap/interfaces": "^2.0", "phpunit/phpunit": "^4.8" }, "type": "library", @@ -348,7 +298,7 @@ ], "description": "PHP/SAP integration tests.", "homepage": "https://php-sap.github.io/", - "time": "2020-01-31T14:32:19+00:00" + "time": "2020-02-03T13:59:15+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -936,6 +886,55 @@ "abandoned": true, "time": "2015-10-02T06:51:40+00:00" }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, { "name": "sebastian/comparator", "version": "1.2.4", @@ -1476,15 +1475,11 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "php-sap/interfaces": 20, - "php-sap/common": 20, - "php-sap/integration-tests": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~5.5.0", + "php": "^5.5", "ext-saprfc": "*" }, "platform-dev": {