Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for PSR-3 #272

Merged
merged 2 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,20 @@ If you have a conflicting package installation that cannot co-exist with our rec

See the [Packagist page for client-implementation](https://packagist.org/providers/php-http/client-implementation) for options.

Contributing
------------
### Enabling Request/Response Logging

Our client library has support for logging the request and response for debugging via PSR-3 compatible logging mechanisms. If the `debug` option is passed into the client and a PSR-3 compatible logger is set in our client's service factory, we will use the logger for debugging purposes.

```php
$client = new \Vonage\Client(new \Vonage\Client\Credentials\Basic('abcd1234', 's3cr3tk3y'), ['debug' => true]);
$logger = new \Monolog\Logger('test');
$logger->pushHandler(new \Monolog\Handler\StreamHandler(__DIR__ . '/log.txt', \Monolog\Logger::DEBUG));
$client->getFactory()->set(\PSR\Log\LoggerInterface::class, $logger);
```

**ENABLING DEBUGING LOGGING HAS THE POTENTIAL FOR LOGGING SENSITIVE INFORMATION, DO NOT ENABLE IN PRODUCTION**

## Contributing

This library is actively developed, and we love to hear from you! Please feel free to [create an issue][issues] or [open a pull request][pulls] with your questions, comments, suggestions and feedback.

Expand All @@ -828,4 +840,3 @@ This library is actively developed, and we love to hear from you! Please feel fr
[spec]: https://github.com/Nexmo/client-library-specification
[issues]: https://github.com/Vonage/vonage-php-core/issues
[pulls]: https://github.com/Vonage/vonage-php-core/pulls

3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"composer/package-versions-deprecated": "^1.11",
"psr/container": "^1.0",
"psr/http-client-implementation": "^1.0",
"vonage/nexmo-bridge": "^0.1.0"
"vonage/nexmo-bridge": "^0.1.0",
"psr/log": "^1.1"
},
"require-dev": {
"guzzlehttp/guzzle": ">=6",
Expand Down
59 changes: 57 additions & 2 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use RuntimeException;
use Vonage\Account\ClientFactory;
use Vonage\Application\ClientFactory as ApplicationClientFactory;
Expand All @@ -41,6 +43,7 @@
use Vonage\Conversion\ClientFactory as ConversionClientFactory;
use Vonage\Entity\EntityInterface;
use Vonage\Insights\ClientFactory as InsightsClientFactory;
use Vonage\Logger\LoggerAwareInterface;
use Vonage\Message\Client as MessageClient;
use Vonage\Numbers\ClientFactory as NumbersClientFactory;
use Vonage\Redact\ClientFactory as RedactClientFactory;
Expand Down Expand Up @@ -68,6 +71,7 @@
use function str_replace;
use function strpos;
use function unserialize;
use Vonage\Logger\LoggerTrait;

/**
* Vonage API Client, allows access to the API from PHP.
Expand All @@ -86,8 +90,10 @@
* @property string restUrl
* @property string apiUrl
*/
class Client
class Client implements LoggerAwareInterface
{
use LoggerTrait;

public const VERSION = '2.5.0';
public const BASE_API = 'https://api.nexmo.com';
public const BASE_REST = 'https://rest.nexmo.com';
Expand All @@ -106,15 +112,25 @@ class Client
*/
protected $client;

/**
* @var bool
*/
protected $debug = false;

/**
* @var ContainerInterface
*/
protected $factory;

/**
* @var LoggerInterface
*/
protected $logger;

/**
* @var array
*/
protected $options = ['show_deprecations' => false];
protected $options = ['show_deprecations' => false, 'debug' => false];

/**
* Create a new API client using the provided credentials.
Expand Down Expand Up @@ -176,6 +192,10 @@ public function __construct(CredentialsInterface $credentials, $options = [], ?C
$this->apiUrl = $options['base_api_url'];
}

if (isset($options['debug'])) {
$this->debug = $options['debug'];
}

$this->setFactory(
new MapFactory(
[
Expand Down Expand Up @@ -532,6 +552,32 @@ public function send(RequestInterface $request): ResponseInterface
/** @noinspection PhpUnnecessaryLocalVariableInspection */
$response = $this->client->sendRequest($request);

if ($this->debug) {
$id = uniqid();
$request->getBody()->rewind();
$response->getBody()->rewind();
$this->log(
LogLevel::DEBUG,
'Request ' . $id,
[
'url' => $request->getUri()->__toString(),
'headers' => $request->getHeaders(),
'body' => explode("\n", $request->getBody()->__toString())
]
);
$this->log(
LogLevel::DEBUG,
'Response ' . $id,
[
'headers ' => $response->getHeaders(),
'body' => explode("\n", $response->getBody()->__toString())
]
);

$request->getBody()->rewind();
$response->getBody()->rewind();
}

return $response;
}

Expand Down Expand Up @@ -637,4 +683,13 @@ protected function getVersion(): string
{
return Versions::getVersion('vonage/client-core');
}

public function getLogger(): ?LoggerInterface
{
if (!$this->logger && $this->getFactory()->has(LoggerInterface::class)) {
$this->setLogger($this->getFactory()->get(LoggerInterface::class));
}

return $this->logger;
}
}
9 changes: 9 additions & 0 deletions src/Client/Factory/MapFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Vonage\Client\Factory;

use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Vonage\Client;
use Vonage\Logger\LoggerAwareInterface;

use function is_callable;
use function sprintf;
Expand Down Expand Up @@ -120,11 +122,18 @@ public function make($key)
$instance->setClient($this->client);
}

if ($instance instanceof LoggerAwareInterface && $this->has(LoggerInterface::class)) {
$instance->setLogger($this->get(LoggerInterface::class));
}

return $instance;
}

public function set($key, $value): void
{
$this->map[$key] = $value;
if (!is_callable($value)) {
$this->cache[$key] = $value;
}
}
}
21 changes: 21 additions & 0 deletions src/Logger/LoggerAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Vonage\Logger;

use Psr\Log\LoggerInterface;

interface LoggerAwareInterface
{
public function getLogger(): ?LoggerInterface;

/**
* @param string|int $level Level of message that we are logging
* @param array<mixed> $context Additional information for context
*/
public function log($level, string $message, array $context = []): void;

/**
* @return self
*/
public function setLogger(LoggerInterface $logger);
}
35 changes: 35 additions & 0 deletions src/Logger/LoggerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Vonage\Logger;

use Psr\Log\LoggerInterface;

trait LoggerTrait
{
/**
* @var LoggerInterface
*/
protected $logger;

public function getLogger(): ?LoggerInterface
{
return $this->logger;
}

/**
* @param string|int $level Level of message that we are logging
* @param array<mixed> $context Additional information for context
*/
public function log($level, string $message, array $context = []): void
{
$logger = $this->getLogger();
if ($logger) {
$logger->log($level, $message, $context);
}
}

public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
}
16 changes: 16 additions & 0 deletions test/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Laminas\Diactoros\Response;
use PHPUnit\Framework\TestCase;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Vonage\Client;
use Vonage\Client\Credentials\Basic;
Expand Down Expand Up @@ -664,6 +665,21 @@ public function testGenericDeleteMethod($url, $params): void
$this->assertRequestBodyIsEmpty($request);
}

public function testLoggerIsNullWhenNotSet(): void
{
$client = new Client($this->basic_credentials, [], $this->http);
$this->assertNull($client->getLogger());
}

public function testCanGetLoggerWhenOneIsSet(): void
{
$client = new Client($this->basic_credentials, [], $this->http);
$logger = $this->prophesize(LoggerInterface::class);
$client->getFactory()->set(LoggerInterface::class, $logger->reveal());

$this->assertNotNull($client->getLogger());
}

public function genericDeleteProvider(): array
{
$baseUrl = 'https://rest.nexmo.com';
Expand Down
46 changes: 46 additions & 0 deletions test/Logger/LoggerTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace VonageTest\Logger;

use Psr\Log\LoggerInterface;
use Vonage\Logger\LoggerTrait;
use PHPUnit\Framework\TestCase;

class LoggerTraitTest extends TestCase
{
public function testCanSetAndGetLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);
$logger = $this->prophesize(LoggerInterface::class)->reveal();
$trait->setLogger($logger);

$this->assertSame($logger, $trait->getLogger());
}

public function testNoLoggerReturnsNull()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);

$this->assertNull($trait->getLogger());
}

public function testCanLogMessageWithLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);
$logger = $this->prophesize(LoggerInterface::class)->reveal();
$trait->setLogger($logger);

$this->assertNull($trait->log('debug', 'This is a message'));
}

public function testLoggingAcceptsMessageWithLogger()
{
/** @var LoggerTrait $trait */
$trait = $this->getMockForTrait(LoggerTrait::class);

$this->assertNull($trait->log('debug', 'This is a message'));
}
}