diff --git a/README.md b/README.md index 10d4da8..49dcb6d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,4 @@ -:warning: :construction: -### Archiviert - -Dieses Repo wurde **archiviert und wird nicht mehr weitergeführt** :file_folder:. Für **produktive Projekte mit der Proffix Rest-API** empfehlen sich mittlerweile andere Sprachen oder Technologien. -Als **erpropte, ausgereifte und aktiv unterhaltene Alternativen** empfehlen wird die von uns unterhaltenen Wrappers für die Proffix Rest-API auszuprobieren: - -- [Golang Wrapper für die Proffix Rest-API](https://github.com/pitwch/go-wrapper-proffix-restapi) :link: -- [Dart Wrapper für die Proffix Rest-API](https://github.com/pitwch/dart_proffix_rest) :link: - # PHP Wrapper für PROFFIX REST-API @@ -205,3 +196,9 @@ $datenbank2 = $pxrest->database(); Im Ordner [/examples](https://github.com/pitwch/php-wrapper-proffix-restapi/tree/master/examples) finden sich weitere, auskommentierte Beispiele. + + +# Weitere Wrapper für die Proffix Rest-API + +- [Golang Wrapper für die Proffix Rest-API](https://github.com/pitwch/go-wrapper-proffix-restapi) :link: +- [Dart Wrapper für die Proffix Rest-API](https://github.com/pitwch/dart_proffix_rest) :link: diff --git a/composer.json b/composer.json index 0de8e58..9534bda 100644 --- a/composer.json +++ b/composer.json @@ -12,13 +12,13 @@ ], "keywords": ["rest", "curl", "proffix", "restful", "api", "proffix rest api","php","wrapper"], "require": { - "php": ">= 5.6.0", + "php": "^8.2", "ext-curl": "*", "ext-json": "*" }, "require-dev": { - "phpunit/phpunit": "*", - "squizlabs/php_codesniffer": "3.*" + "phpunit/phpunit": "^11.0", + "squizlabs/php_codesniffer": "^3.9" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 516dabe..0f8ad28 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9555d0a84873fc7ad4f614a4b2613d80", + "content-hash": "0f6dc88a28ae8c7c17426dc196bead18", "packages": [], "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.13.0", + "version": "1.13.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", - "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", "shasum": "" }, "require": { @@ -57,7 +57,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" }, "funding": [ { @@ -65,20 +65,20 @@ "type": "tidelift" } ], - "time": "2025-02-12T12:17:51+00:00" + "time": "2025-04-29T12:36:36+00:00" }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -121,9 +121,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", @@ -245,23 +245,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.8", + "version": "11.0.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "418c59fd080954f8c4aa5631d9502ecda2387118" + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/418c59fd080954f8c4aa5631d9502ecda2387118", - "reference": "418c59fd080954f8c4aa5631d9502ecda2387118", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.3.1", + "nikic/php-parser": "^5.4.0", "php": ">=8.2", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-text-template": "^4.0.1", @@ -273,7 +273,7 @@ "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^11.5.0" + "phpunit/phpunit": "^11.5.2" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -311,7 +311,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.8" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.9" }, "funding": [ { @@ -319,7 +319,7 @@ "type": "github" } ], - "time": "2024-12-11T12:34:27+00:00" + "time": "2025-02-25T13:26:39+00:00" }, { "name": "phpunit/php-file-iterator", @@ -568,16 +568,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.7", + "version": "11.5.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d" + "reference": "86ebcd8a3dbcd1857d88505109b2a2b376501cde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e1cb706f019e2547039ca2c839898cd5f557ee5d", - "reference": "e1cb706f019e2547039ca2c839898cd5f557ee5d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86ebcd8a3dbcd1857d88505109b2a2b376501cde", + "reference": "86ebcd8a3dbcd1857d88505109b2a2b376501cde", "shasum": "" }, "require": { @@ -587,24 +587,24 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.1", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.8", + "phpunit/php-code-coverage": "^11.0.9", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", - "sebastian/code-unit": "^3.0.2", - "sebastian/comparator": "^6.3.0", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.1", "sebastian/diff": "^6.0.2", - "sebastian/environment": "^7.2.0", + "sebastian/environment": "^7.2.1", "sebastian/exporter": "^6.3.0", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", - "sebastian/type": "^5.1.0", + "sebastian/type": "^5.1.2", "sebastian/version": "^5.0.2", "staabm/side-effects-detector": "^1.0.5" }, @@ -649,7 +649,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.23" }, "funding": [ { @@ -660,12 +660,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2025-02-06T16:10:05+00:00" + "time": "2025-06-13T05:47:49+00:00" }, { "name": "sebastian/cli-parser", @@ -726,16 +734,16 @@ }, { "name": "sebastian/code-unit", - "version": "3.0.2", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca" + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", - "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", "shasum": "" }, "require": { @@ -771,7 +779,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/code-unit/issues", "security": "https://github.com/sebastianbergmann/code-unit/security/policy", - "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" }, "funding": [ { @@ -779,7 +787,7 @@ "type": "github" } ], - "time": "2024-12-12T09:59:06+00:00" + "time": "2025-03-19T07:56:08+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -839,16 +847,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.0", + "version": "6.3.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115" + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115", - "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", "shasum": "" }, "require": { @@ -867,7 +875,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "6.2-dev" + "dev-main": "6.3-dev" } }, "autoload": { @@ -907,7 +915,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.0" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" }, "funding": [ { @@ -915,7 +923,7 @@ "type": "github" } ], - "time": "2025-01-06T10:28:19+00:00" + "time": "2025-03-07T06:57:01+00:00" }, { "name": "sebastian/complexity", @@ -1044,23 +1052,23 @@ }, { "name": "sebastian/environment", - "version": "7.2.0", + "version": "7.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", - "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "suggest": { "ext-posix": "*" @@ -1096,15 +1104,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2024-07-03T04:54:44+00:00" + "time": "2025-05-21T11:55:47+00:00" }, { "name": "sebastian/exporter", @@ -1484,16 +1504,16 @@ }, { "name": "sebastian/type", - "version": "5.1.0", + "version": "5.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac" + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac", - "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", "shasum": "" }, "require": { @@ -1529,7 +1549,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/type/issues", "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" }, "funding": [ { @@ -1537,7 +1557,7 @@ "type": "github" } ], - "time": "2024-09-17T13:12:04+00:00" + "time": "2025-03-18T13:35:50+00:00" }, { "name": "sebastian/version", @@ -1595,16 +1615,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.11.3", + "version": "3.13.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10" + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", + "reference": "1b71b4dd7e7ef651ac749cea67e513c0c832f4bd", "shasum": "" }, "require": { @@ -1671,11 +1691,11 @@ "type": "open_collective" }, { - "url": "https://thanks.dev/phpcsstandards", + "url": "https://thanks.dev/u/gh/phpcsstandards", "type": "thanks_dev" } ], - "time": "2025-01-23T17:04:15+00:00" + "time": "2025-06-12T15:04:34+00:00" }, { "name": "staabm/side-effects-detector", @@ -1786,7 +1806,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">= 5.6.0", + "php": "^8.2", "ext-curl": "*", "ext-json": "*" }, diff --git a/examples/adresse-read-filter.php b/examples/adresse-read-filter.php index 2ce1cc4..fae9c59 100644 --- a/examples/adresse-read-filter.php +++ b/examples/adresse-read-filter.php @@ -1,21 +1,22 @@ '112a5a90fe28b23ed2c776562a7d1043957b5b79fad242b10141254b4de59028','limit'=>1)); + ['ADR', 'STU'], + ['key' => '112a5a90fe28b23ed2c776562a7d1043957b5b79fad242b10141254b4de59028', 'limit' => 1] +); -$adressefilter = $pxrest->Get("ADR/Adresse",array('filter'=>'Vorname@="Max"')); // Query for all adresses + Vorname contains "Max" +$adressefilter = $pxrest->get("ADR/Adresse", ['filter' => 'Vorname@="Max"']); // Query for all adresses + Vorname contains "Max" foreach ($adressefilter as $adresse) { - echo $adresse->Name." ".$adresse->Vorname."\n"; // Echo Name + Vorname + newline + echo $adresse->Name . " " . $adresse->Vorname . "\n"; // Echo Name + Vorname + newline } @@ -23,4 +24,5 @@ Muster Max Müller Max Meier Maximilian -Claudius Maximus \ No newline at end of file +Claudius Maximus +*/ \ No newline at end of file diff --git a/src/RestAPIWrapperProffix/Client.php b/src/RestAPIWrapperProffix/Client.php index 27712e0..1ff6f38 100644 --- a/src/RestAPIWrapperProffix/Client.php +++ b/src/RestAPIWrapperProffix/Client.php @@ -6,51 +6,115 @@ use Pitwch\RestAPIWrapperProffix\HttpClient\HttpClient; +/** + * Class Client + * + * @package Pitwch\RestAPIWrapperProffix + */ class Client { const VERSION = '1.3'; - public $http; - + /** + * @var HttpClient + */ + protected $http; + + /** + * Client constructor. + * + * @param string $url The Proffix API URL + * @param string $apiDatabase The Proffix Database + * @param string $apiUser The Proffix User + * @param string $apiPassword The Proffix Password + * @param array $apiModules The required Proffix Modules + * @param array $options Additional options + * + * @throws HttpClient\HttpClientException + */ public function __construct($url, $apiDatabase, $apiUser, $apiPassword, $apiModules, $options = []) { $this->http = new HttpClient($url, $apiDatabase, $apiUser, $apiPassword, $apiModules, $options); } + /** + * @param string $endpoint + * @param array $data + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ public function post($endpoint, $data) { return $this->http->request($endpoint, 'POST', $data); } + /** + * @param string $endpoint + * @param array $data + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ public function put($endpoint, $data) { return $this->http->request($endpoint, 'PUT', $data); } + /** + * @param string $endpoint + * @param array $parameters + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ public function get($endpoint, $parameters = []) { return $this->http->request($endpoint, 'GET', [], $parameters); } + /** + * @param string $endpoint + * @param array $parameters + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ public function delete($endpoint, $parameters = []) { return $this->http->request($endpoint, 'DELETE', [], $parameters); } - public function info($px_api_key = ''){ - - return $this->http->request('PRO/Info', 'GET', [], array('key'=>$px_api_key),false); - + /** + * @param string $px_api_key + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ + public function info($px_api_key = '') + { + return $this->http->request('PRO/Info', 'GET', [], ['key' => $px_api_key], false); } - public function database($px_api_key = ''){ - - return $this->http->request('PRO/Datenbank', 'GET', [], array('key'=>$px_api_key),false); - + /** + * @param string $px_api_key + * + * @return mixed + * + * @throws HttpClient\HttpClientException + */ + public function database($px_api_key = '') + { + return $this->http->request('PRO/Datenbank', 'GET', [], ['key' => $px_api_key], false); } diff --git a/src/RestAPIWrapperProffix/HttpClient/HttpClient.php b/src/RestAPIWrapperProffix/HttpClient/HttpClient.php index d260f4a..e554c99 100644 --- a/src/RestAPIWrapperProffix/HttpClient/HttpClient.php +++ b/src/RestAPIWrapperProffix/HttpClient/HttpClient.php @@ -11,20 +11,68 @@ +/** + * Class HttpClient + * + * @package Pitwch\RestAPIWrapperProffix\HttpClient + */ class HttpClient { - protected $ch; + /** + * @var string The Proffix API URL + */ protected $url; + + /** + * @var string The Proffix API Database + */ protected $apiDatabase; + + /** + * @var array The Proffix API Modules + */ protected $apiModules; + + /** + * @var string The Proffix API User + */ protected $apiUser; + + /** + * @var string The Proffix API Password + */ protected $apiPassword; + + /** + * @var Options The options for the client + */ protected $options; + + /** + * @var Request The request object + */ public $request; + + /** + * @var Response The response object + */ public $response; - private $responseHeaders; + + /** + * @var string The Proffix Session ID + */ protected $pxSessionId; + /** + * @var resource|\CurlHandle The cURL handle + */ + private $ch; + + /** + * @var array The response headers + */ + private $responseHeaders = []; + /** * HttpClient constructor. * @param $url @@ -35,6 +83,18 @@ class HttpClient * @param $options * @throws HttpClientException */ + /** + * HttpClient constructor. + * + * @param string $url The Proffix API URL + * @param string $apiDatabase The Proffix Database + * @param string $apiUser The Proffix User + * @param string $apiPassword The Proffix Password + * @param array $apiModules The required Proffix Modules + * @param array $options Additional options + * + * @throws HttpClientException + */ public function __construct($url, $apiDatabase, $apiUser, $apiPassword, $apiModules, $options) { if (!\function_exists('curl_version')) { @@ -47,12 +107,13 @@ public function __construct($url, $apiDatabase, $apiUser, $apiPassword, $apiModu $this->apiPassword = $apiPassword; $this->apiDatabase = $apiDatabase; $this->apiModules = $apiModules; - //$this->pxSessionId = $this->login(); } /** + * Check if the connection is SSL + * * @return bool */ protected function isSsl() @@ -62,7 +123,10 @@ protected function isSsl() /** - * @param $url + * Build the API URL + * + * @param string $url + * * @return string */ protected function buildApiUrl($url) @@ -73,8 +137,11 @@ protected function buildApiUrl($url) /** - * @param $url - * @param array $parameters + * Build the URL with query parameters + * + * @param string $url + * @param array $parameters + * * @return string */ protected function buildUrlQuery($url, $parameters = []) @@ -102,20 +169,25 @@ protected function buildUrlQuery($url, $parameters = []) } /** + * Build the JSON for the login request + * * @return array */ protected function buildLoginJson() { - $loginJson = Array("Benutzer" => $this->apiUser, - "Passwort" => $this->apiPassword, - "Datenbank" => Array("Name" => $this->apiDatabase), - "Module" => explode(",", $this->apiModules) - ); + $loginJson = [ + 'Benutzer' => $this->apiUser, + 'Passwort' => $this->apiPassword, + 'Datenbank' => ['Name' => $this->apiDatabase], + 'Module' => is_array($this->apiModules) ? $this->apiModules : explode(',', $this->apiModules) + ]; return $loginJson; } /** + * Build the login URL + * * @return string */ protected function buildLoginUrl() @@ -125,99 +197,83 @@ protected function buildLoginUrl() } /** - * @return mixed|string + * Login to Proffix + * + * @return string The PxSessionId + * + * @throws HttpClientException */ protected function login() { - $headers = []; - + $this->initCurl(); - $headerarray = array("Cache-Control: no-cache","Content-Type: application/json","PxSessionId:" . $this->pxSessionId); + $body = \json_encode($this->buildLoginJson()); + $headers = [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($body) + ]; + curl_setopt($this->ch, CURLOPT_URL, $this->buildLoginUrl()); + curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($this->ch, CURLOPT_POSTFIELDS, $body); + curl_setopt($this->ch, CURLOPT_HEADER, true); + $response = curl_exec($this->ch); + if (curl_errno($this->ch)) { + throw new HttpClientException('cURL error: ' . curl_error($this->ch), curl_errno($this->ch), $this->request, $this->response); + } - $body = \json_encode($this->buildLoginJson()); - $curl = curl_init(); - - curl_setopt_array($curl, array( - CURLOPT_URL => $this->buildLoginUrl(), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", - CURLOPT_MAXREDIRS => 10, - CURLOPT_TIMEOUT => $this->options->getTimeout(), - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HEADER => true, - CURLOPT_POSTFIELDS => $body, - CURLOPT_HTTPHEADER => $headerarray, - )); - - $response = curl_exec($curl); - - $err = curl_error($curl); - - curl_close($curl); - - if ($err) { - return "cURL Error #:" . $err; - } else { - $lines = \explode("\n", $response); - $lines = \array_filter($lines, 'trim'); - - foreach ($lines as $index => $line) { - // Remove HTTP/xxx params. - if (strpos($line, ': ') === false) { - continue; - } + $headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); + $header = substr($response, 0, $headerSize); - list($key, $value) = \explode(': ', $line); + $this->pxSessionId = $this->extractSessionId($header); - $headers[$key] = isset($headers[$key]) ? $headers[$key] . ', ' . trim($value) : trim($value); - } - return $headers['PxSessionId']; + if (empty($this->pxSessionId)) { + throw new HttpClientException('Failed to retrieve PxSessionId from login response.', 401, $this->request, $this->response); } - + return $this->pxSessionId; } /** - * @return bool|string + * Logout from Proffix + * + * @return bool + * + * @throws HttpClientException */ protected function logout() { + if (empty($this->pxSessionId)) { + return true; + } + + $this->initCurl(); + $headers = [ + 'PxSessionId: ' . $this->pxSessionId + ]; + + curl_setopt($this->ch, CURLOPT_URL, $this->buildLoginUrl()); + curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers); + + curl_exec($this->ch); + + if (curl_errno($this->ch)) { + throw new HttpClientException('cURL error on logout: ' . curl_error($this->ch), curl_errno($this->ch), $this->request, $this->response); + } - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_URL => $this->buildLoginUrl(), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", - CURLOPT_MAXREDIRS => 10, - CURLOPT_TIMEOUT => $this->options->getTimeout(), - CURLOPT_CUSTOMREQUEST => "DELETE", - CURLOPT_RETURNTRANSFER => true, - CURLOPT_HEADER => true, - CURLOPT_HTTPHEADER => array( - "Cache-Control: no-cache", - "Content-Type: application/json", - "PxSessionId:" . $this->pxSessionId, - ), - )); - - $response = curl_exec($curl); - - $err = curl_error($curl); - - curl_close($curl); - - if ($err) { - return "cURL Error #:" . $err; - } else return true; + $this->pxSessionId = null; + return true; } /** - * @param $method + * Set the HTTP method for the cURL request + * + * @param string $method */ protected function setupMethod($method) { @@ -229,9 +285,13 @@ protected function setupMethod($method) } /** + * Get the request headers + * * @param bool $sendData + * * @return array - * @throws \Pitwch\RestAPIWrapperProffix\HttpClient\HttpClientException + * + * @throws HttpClientException */ protected function getRequestHeaders($sendData = false) { @@ -249,28 +309,25 @@ protected function getRequestHeaders($sendData = false) } /** - * @param $endpoint - * @param $method - * @param array $data - * @param array $parameters - * @return mixed - * @throws \Pitwch\RestAPIWrapperProffix\HttpClient\HttpClientException + * Create the request object + * + * @param string $endpoint + * @param string $method + * @param array $data + * @param array $parameters + * + * @return Request + * + * @throws HttpClientException */ - protected function createRequest($endpoint, $method, $data = [], $parameters = [],$nologin = false) + protected function createRequest($endpoint, $method, $data = [], $parameters = []) { $body = ''; $url = $this->url . $endpoint; $hasData = !empty($data); - - // Setup method. - $this->setupMethod($method); - - - // Include post fields. if ($hasData) { $body = \json_encode($data); - \curl_setopt($this->ch, CURLOPT_POSTFIELDS, $body); } $this->request = new Request( @@ -280,16 +337,19 @@ protected function createRequest($endpoint, $method, $data = [], $parameters = [ $this->getRequestHeaders($hasData), $body ); - return $this->getRequest(); + + return $this->request; } /** + * Get the response headers + * * @return array */ protected function getResponseHeaders() { $headers = []; - $lines = \explode("\n", $this->responseHeaders); + $lines = explode("\n", (string)$this->responseHeaders); $lines = \array_filter($lines, 'trim'); foreach ($lines as $index => $line) { @@ -307,10 +367,12 @@ protected function getResponseHeaders() } /** - * @return mixed - * @throws \Pitwch\RestAPIWrapperProffix\HttpClient\HttpClientException + * Create the response object + * + * @return Response + * + * @throws HttpClientException */ - protected function createResponse() { @@ -333,7 +395,7 @@ protected function createResponse() } /** - * + * Set the default cURL settings */ protected function setDefaultCurlSettings() { @@ -356,42 +418,48 @@ protected function setDefaultCurlSettings() } /** - * @param $parsedResponse + * Check for errors in the response + * + * @param mixed $parsedResponse + * * @throws HttpClientException */ protected function lookForErrors($parsedResponse) { // Any non-200/201/202/204 response code indicates an error. - if (!\in_array($this->response->getCode(), ['200', '201', '202','204'])) { - $errors = isset($parsedResponse->errors) ? $parsedResponse->errors : $parsedResponse; - if (($errors->Fields)) { - - $errorMessage = print_r($errors); - $errorCode = $this->response->getCode(); - } else { - $errorMessage = $errors->Message; - $errorCode = $this->response->getCode(); + if (!in_array($this->response->getCode(), ['200', '201', '202', '204'])) { + $errorMessage = 'An unknown error occurred'; + if (isset($parsedResponse->Message)) { + $errorMessage = $parsedResponse->Message; + } elseif (is_string($parsedResponse)) { + $errorMessage = $parsedResponse; } throw new HttpClientException( - \sprintf('Message: %s Code: %s', $errorMessage, $errorCode), + sprintf('Error: %s', $errorMessage), $this->response->getCode(), $this->request, $this->response ); - } } - //TODO - protected function parsePxErrorMessage($errors){ + /** + * @param $errors + * @return array + */ + protected function parsePxErrorMessage($errors) + { foreach ($errors as $error){ $clean[] = $error; } } /** + * Process the response + * * @return mixed - * @throws \Pitwch\RestAPIWrapperProffix\HttpClient\HttpClientException + * + * @throws HttpClientException */ protected function processResponse() { @@ -418,38 +486,36 @@ protected function processResponse() * @return mixed * @throws HttpClientException */ - public function request($endpoint, $method, $data = [], $parameters = [],$login = true) + public function request($endpoint, $method, $data = [], $parameters = [], $login = true) { - //Login - $this->pxSessionId = $login ? $this->login() : ''; - // Initialize cURL. - $this->ch = \curl_init(); + if ($login && empty($this->pxSessionId)) { + $this->login(); + } - // Set request args. - $request = $this->createRequest($endpoint, $method, $data, $parameters); + $this->initCurl(); - // Default cURL settings. + $this->createRequest($endpoint, $method, $data, $parameters); $this->setDefaultCurlSettings(); - // Get response. - $response = $this->createResponse(); - - //Logout - $login ? $this->logout($this->pxSessionId) : ''; + // Setup method. + $this->setupMethod($method); - // Check for cURL errors. - if (\curl_errno($this->ch)) { - throw new HttpClientException('cURL Error: ' . \curl_error($this->ch), 0, $request, $response); + // Include post fields. + if (!empty($data)) { + $body = \json_encode($data); + \curl_setopt($this->ch, CURLOPT_POSTFIELDS, $body); } - \curl_close($this->ch); + $this->createResponse(); + $this->lookForErrors($this->processResponse()); return $this->processResponse(); } - /** - * @return mixed + * Get the request object + * + * @return Request */ public function getRequest() { @@ -457,11 +523,53 @@ public function getRequest() } /** - * @return mixed + * Get the response object + * + * @return Response */ public function getResponse() { return $this->response; } + /** + * Initialize the cURL handle + */ + private function initCurl() + { + if (!$this->ch) { + $this->ch = curl_init(); + } + } + + /** + * Extract the session ID from the response headers + * + * @param string $header + * + * @return string|null + */ + private function extractSessionId($header) + { + foreach (explode("\r\n", $header) as $line) { + if (strpos($line, 'PxSessionId:') === 0) { + return trim(substr($line, strlen('PxSessionId:'))); + } + } + + return null; + } + + /** + * Destructor + */ + public function __destruct() + { + if ($this->ch) { + if(!empty($this->pxSessionId)){ + $this->logout(); + } + curl_close($this->ch); + } + } } diff --git a/src/RestAPIWrapperProffix/HttpClient/HttpClientException.php b/src/RestAPIWrapperProffix/HttpClient/HttpClientException.php index 0436d6f..377aaf6 100644 --- a/src/RestAPIWrapperProffix/HttpClient/HttpClientException.php +++ b/src/RestAPIWrapperProffix/HttpClient/HttpClientException.php @@ -6,14 +6,33 @@ use Pitwch\RestAPIWrapperProffix\HttpClient\Response; +/** + * Class HttpClientException + * + * @package Pitwch\RestAPIWrapperProffix\HttpClient + */ class HttpClientException extends \Exception { + /** + * @var Request + */ private $request; + /** + * @var Response + */ private $response; + /** + * HttpClientException constructor. + * + * @param string $message + * @param int $code + * @param Request $request + * @param Response $response + */ public function __construct($message, $code, Request $request, Response $response) { parent::__construct($message, $code); @@ -23,12 +42,18 @@ public function __construct($message, $code, Request $request, Response $respons } + /** + * @return Request + */ public function getRequest() { return $this->request; } + /** + * @return Response + */ public function getResponse() { return $this->response; diff --git a/src/RestAPIWrapperProffix/HttpClient/Options.php b/src/RestAPIWrapperProffix/HttpClient/Options.php index 42b1ec3..6c68d57 100644 --- a/src/RestAPIWrapperProffix/HttpClient/Options.php +++ b/src/RestAPIWrapperProffix/HttpClient/Options.php @@ -3,6 +3,11 @@ namespace Pitwch\RestAPIWrapperProffix\HttpClient; +/** + * Class Options + * + * @package Pitwch\RestAPIWrapperProffix\HttpClient + */ class Options { @@ -12,52 +17,89 @@ class Options const PX_API_PREFIX = '/pxapi/'; + /** + * User agent string + */ const USER_AGENT = 'php-wrapper-proffix-restapi'; + /** + * Login endpoint + */ const LOGIN_ENDPOINT = 'PRO/Login'; + /** + * Endpoints that do not require login + */ const NO_LOGIN = array('PRO/Info', 'PRO/Datenbank'); - private $options; - - - public function __construct($options) + /** + * @var array + */ + private $options = []; + + /** + * Options constructor. + * + * @param array $options + */ + public function __construct(array $options = []) { $this->options = $options; } + /** + * @return string + */ public function getVersion() { return isset($this->options['version']) ? $this->options['version'] : self::VERSION; } + /** + * @return bool + */ public function verifySsl() { return isset($this->options['verify_ssl']) ? (bool)$this->options['verify_ssl'] : true; } + /** + * @return int + */ public function getTimeout() { return isset($this->options['timeout']) ? (int)$this->options['timeout'] : self::TIMEOUT; } + /** + * @return string + */ public function apiPrefix() { return isset($this->options['api_prefix']) ? $this->options['api_prefix'] : self::PX_API_PREFIX; } + /** + * @return string + */ public function getLoginEndpoint() { return isset($this->options['login_endpoint']) ? $this->options['login_endpoint'] : self::LOGIN_ENDPOINT; } + /** + * @return string + */ public function getApiKey() { return isset($this->options['key']) ? $this->options['key'] : ''; } + /** + * @return string + */ public function userAgent() { return isset($this->options['user_agent']) ? $this->options['user_agent'] : self::USER_AGENT; diff --git a/src/RestAPIWrapperProffix/HttpClient/Request.php b/src/RestAPIWrapperProffix/HttpClient/Request.php index 7bbf1c6..22611b4 100644 --- a/src/RestAPIWrapperProffix/HttpClient/Request.php +++ b/src/RestAPIWrapperProffix/HttpClient/Request.php @@ -3,16 +3,45 @@ namespace Pitwch\RestAPIWrapperProffix\HttpClient; +/** + * Class Request + * + * @package Pitwch\RestAPIWrapperProffix\HttpClient + */ class Request { + /** + * @var string + */ private $url; + /** + * @var string + */ private $method; + /** + * @var array + */ private $parameters; + /** + * @var array + */ private $headers; + /** + * @var string + */ private $body; - public function __construct($url = '', $method = 'POST', $parameters = [], $headers = [], $body = '') + /** + * Request constructor. + * + * @param string $url + * @param string $method + * @param array $parameters + * @param array $headers + * @param string $body + */ + public function __construct($url = '', $method = 'GET', $parameters = [], $headers = [], $body = '') { $this->url = $url; $this->method = $method; @@ -22,52 +51,79 @@ public function __construct($url = '', $method = 'POST', $parameters = [], $head } + /** + * @param string $url + */ public function setUrl($url) { $this->url = $url; } + /** + * @param string $method + */ public function setMethod($method) { $this->method = $method; } + /** + * @param array $parameters + */ public function setParameters($parameters) { $this->parameters = $parameters; } + /** + * @param array $headers + */ public function setHeaders($headers) { $this->headers = $headers; } + /** + * @param string $body + */ public function setBody($body) { $this->body = $body; } + /** + * @return string + */ public function getUrl() { return $this->url; } + /** + * @return string + */ public function getMethod() { return $this->method; } + /** + * @return array + */ public function getParameters() { return $this->parameters; } + /** + * @return array + */ public function getHeaders() { return $this->headers; @@ -86,6 +142,9 @@ public function getRawHeaders() } + /** + * @return string + */ public function getBody() { return $this->body; diff --git a/src/RestAPIWrapperProffix/HttpClient/Response.php b/src/RestAPIWrapperProffix/HttpClient/Response.php index 5b4da5b..fdc4a0d 100644 --- a/src/RestAPIWrapperProffix/HttpClient/Response.php +++ b/src/RestAPIWrapperProffix/HttpClient/Response.php @@ -4,14 +4,35 @@ namespace Pitwch\RestAPIWrapperProffix\HttpClient; +/** + * Class Response + * + * @package Pitwch\RestAPIWrapperProffix\HttpClient + */ class Response { + /** + * @var int + */ private $code; + /** + * @var array + */ private $headers; + /** + * @var string + */ private $body; + /** + * Response constructor. + * + * @param int $code + * @param array $headers + * @param string $body + */ public function __construct($code = 0, $headers = [], $body = '') { $this->code = $code; @@ -37,17 +58,30 @@ public function setBody($body) } + /** + * Returns the HTTP status code. + * + * @return int + */ public function getCode() { return $this->code; } + /** + * Returns the HTTP headers. + * + * @return array + */ public function getHeaders() { return $this->headers; } + /** + * @return string + */ public function getBody() { return $this->body; diff --git a/tests/RestAPIWrapperProffix/HttpClientTest.php b/tests/RestAPIWrapperProffix/HttpClientTest.php new file mode 100644 index 0000000..d66faaa --- /dev/null +++ b/tests/RestAPIWrapperProffix/HttpClientTest.php @@ -0,0 +1,44 @@ +defaultOptions = [ + 'url' => 'http://fake-api.proffix.com', + 'apiDatabase' => 'FAKEDB', + 'apiUser' => 'testuser', + 'apiPassword' => 'password', + 'apiModules' => ['CRM', 'ADR'], + 'options' => [] // Default HttpClient Options + ]; + + $this->httpClient = new HttpClient( + $this->defaultOptions['url'], + $this->defaultOptions['apiDatabase'], + $this->defaultOptions['apiUser'], + $this->defaultOptions['apiPassword'], + $this->defaultOptions['apiModules'], + $this->defaultOptions['options'] + ); + } + + public function testHttpClientCanBeInstantiated(): void + { + $this->assertInstanceOf(HttpClient::class, $this->httpClient); + } + + // More tests will be added here, e.g., for login, request methods, error handling. + // These will likely require mocking cURL functions or HTTP responses. + +}