diff --git a/composer.json b/composer.json index b045d46..14b7b20 100644 --- a/composer.json +++ b/composer.json @@ -3,17 +3,18 @@ "description": "PHP errors Catcher module for Hawk.so", "keywords": ["hawk", "php", "error", "catcher"], "type": "library", - "version": "2.2.8", + "version": "2.2.9", "license": "MIT", "require": { "ext-curl": "*", "ext-json": "*", "php": "^7.2 || ^8.0", - "jean85/pretty-package-versions": "^1.5 || ^2.0" + "jean85/pretty-package-versions": "^1.5 || ^2.0", + "guzzlehttp/guzzle": "^7.9" }, "require-dev": { "phpunit/phpunit": "^8.2", - "friendsofphp/php-cs-fixer": "^2.15", + "friendsofphp/php-cs-fixer": "^2.19", "symfony/var-dumper": "^5.2" }, "autoload": { diff --git a/src/Catcher.php b/src/Catcher.php index 17f84c1..44a811e 100644 --- a/src/Catcher.php +++ b/src/Catcher.php @@ -6,7 +6,6 @@ use Hawk\Addons\Environment; use Hawk\Addons\Headers; -use Hawk\Transport\CurlTransport; use Throwable; /** @@ -157,7 +156,7 @@ private function __construct(array $options) $builder->registerAddon(new Headers()); $builder->registerAddon(new Environment()); - $transport = new CurlTransport($options->getUrl(), $options->getTimeout()); + $transport = Transport::init($options); $this->handler = new Handler($options, $transport, $builder); diff --git a/src/Exception/TransportException.php b/src/Exception/TransportException.php new file mode 100644 index 0000000..af4657d --- /dev/null +++ b/src/Exception/TransportException.php @@ -0,0 +1,7 @@ +options = $options; diff --git a/src/Options.php b/src/Options.php index 52f3886..f9434e9 100644 --- a/src/Options.php +++ b/src/Options.php @@ -44,6 +44,11 @@ class Options */ private $timeout = 2; + /** + * @var string + */ + private $transport = 'curl'; + /** * Map of accepted option keys to class properties. */ @@ -59,6 +64,7 @@ class Options 'beforeSend' => 'beforeSend', 'before_send' => 'beforeSend', 'timeout' => 'timeout', + 'transport' => 'transport', ]; /** @@ -91,6 +97,7 @@ private function setOption(string $key, $value): void case 'integrationToken': case 'release': case 'url': + case 'transport': if (!is_string($value)) { throw new \InvalidArgumentException("Option '$key' must be a string."); } @@ -169,4 +176,9 @@ public function getTimeout(): int { return $this->timeout; } + + public function getTransport(): string + { + return $this->transport; + } } diff --git a/src/Transport.php b/src/Transport.php new file mode 100644 index 0000000..5c9963c --- /dev/null +++ b/src/Transport.php @@ -0,0 +1,108 @@ +getTransport(), $transports)) { + throw new TransportException('Invalid transport specified'); + } + + return new $transports[$options->getTransport()]($options); + } + + /** + * @return string[] + */ + public static function getTransports(): array + { + return [ + 'curl' => CurlTransport::class, + 'guzzle' => GuzzleTransport::class, + ]; + } + + /** + * @param Options $options + */ + public function __construct(Options $options) + { + $this->url = $options->getUrl(); + $this->timeout = $options->getTimeout(); + } + + /** + * Returns URL that object must send an Event + * + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * Returns total timeout of the request in seconds + * + * @return int + */ + public function getTimeout(): int + { + return $this->timeout; + } + + /** + * Sends an Event + * + * @param Event $event + * + * @return mixed + */ + public function send(Event $event) + { + $response = $this->_send($event); + + try { + $data = json_decode($response, true); + } catch (\Exception $e) { + $data = null; + } + + return $data; + } + + + abstract protected function _send(Event $event): string; +} diff --git a/src/Transport/CurlTransport.php b/src/Transport/CurlTransport.php index 1b55e5a..9520877 100644 --- a/src/Transport/CurlTransport.php +++ b/src/Transport/CurlTransport.php @@ -5,51 +5,30 @@ namespace Hawk\Transport; use Hawk\Event; +use Hawk\Options; +use Hawk\Transport; /** * Class CurlTransport is a transport object * * @package Hawk\Transport */ -class CurlTransport implements TransportInterface +class CurlTransport extends Transport { - /** - * URL to send occurred event - * - * @var string - */ - private $url; - - /** - * CURLOPT_TIMEOUT - * - * @var int - */ - private $timeout; - /** * CurlTransport constructor. * - * @param string $url - */ - public function __construct(string $url, int $timeout) - { - $this->url = $url; - $this->timeout = $timeout; - } - - /** - * @inheritDoc + * @param Options $options */ - public function getUrl(): string + public function __construct(Options $options) { - return $this->url; + parent::__construct($options); } /** * @inheritDoc */ - public function send(Event $event) + protected function _send(Event $event): string { /** * If php-curl is not available then throw an exception @@ -59,12 +38,12 @@ public function send(Event $event) } $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, $this->url); + curl_setopt($curl, CURLOPT_URL, $this->getUrl()); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($event, JSON_UNESCAPED_UNICODE)); curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($curl, CURLOPT_TIMEOUT, $this->getTimeout()); $response = curl_exec($curl); curl_close($curl); diff --git a/src/Transport/GuzzleTransport.php b/src/Transport/GuzzleTransport.php index 6ff5153..0e87164 100644 --- a/src/Transport/GuzzleTransport.php +++ b/src/Transport/GuzzleTransport.php @@ -5,34 +5,46 @@ namespace Hawk\Transport; use Hawk\Event; +use Hawk\Options; +use Hawk\Transport; /** * Class GuzzleTransport * * @package Hawk\Transport */ -class GuzzleTransport implements TransportInterface +class GuzzleTransport extends Transport { - private $url; - - public function __construct(string $url) - { - $this->url = $url; - } + /** + * @var \GuzzleHttp\Client + */ + private $client; /** - * @inheritDoc + * GuzzleTransport constructor. + * + * @param Options $options */ - public function getUrl(): string + public function __construct(Options $options) { - return $this->url; + parent::__construct($options); + + $this->client = new \GuzzleHttp\Client(); } /** * @inheritDoc */ - public function send(Event $event): void + protected function _send(Event $event): string { - // TODO: Implement send() method. + $response = $this->client->post($this->getUrl(), [ + 'headers' => [ + 'Content-Type' => 'application/json', + ], + 'body' => json_encode($event, JSON_UNESCAPED_UNICODE), + 'timeout' => $this->getTimeout(), + ]); + + return $response->getBody()->getContents(); } } diff --git a/src/Transport/TransportInterface.php b/src/Transport/TransportInterface.php deleted file mode 100644 index dcc2428..0000000 --- a/src/Transport/TransportInterface.php +++ /dev/null @@ -1,31 +0,0 @@ -assertEmpty($options->getIntegrationToken()); $this->assertEmpty($options->getRelease()); $this->assertEquals('https://k1.hawk.so/', $options->getUrl()); + $this->assertEquals(2, $options->getTimeout()); + $this->assertEquals('curl', $options->getTransport()); $this->assertEquals(error_reporting(), $options->getErrorTypes()); + $this->assertArrayHasKey($options->getTransport(), Transport::getTransports()); } public function testCustomOptions(): void @@ -27,8 +31,9 @@ public function testCustomOptions(): void 'integrationToken' => 'myToken', 'release' => '123', 'error_types' => 11, - 'beforeSend' => function () { - } + 'beforeSend' => function () {}, + 'timeout' => 60, + 'transport' => 'guzzle', ]; $options = new Options($config); @@ -37,7 +42,9 @@ public function testCustomOptions(): void 'integrationToken' => $options->getIntegrationToken(), 'release' => $options->getRelease(), 'error_types' => $options->getErrorTypes(), - 'beforeSend' => $options->getBeforeSend() + 'beforeSend' => $options->getBeforeSend(), + 'timeout' => $options->getTimeout(), + 'transport' => $options->getTransport(), ]); } }