diff --git a/.travis.yml b/.travis.yml index a0931eb..23364b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,24 @@ language: php -matrix: - fast_finish: true - include: - - php: 5.5 - - php: 5.6 - - php: 7 - - php: hhvm - allow_failures: - - php: 7 - - php: hhvm +php: + - 7.0 + - 7.1 + - 7.2 + +env: + - COMPOSER_FLAGS=--prefer-lowest + - COMPOSER_FLAGS= + +before_install: + - phpenv config-rm xdebug.ini install: - - travis_retry composer install --no-interaction --ignore-platform-reqs --prefer-source - - composer info -i + - composer update --no-interaction --no-suggest --prefer-dist $COMPOSER_FLAGS script: - - ./vendor/bin/phpunit + - vendor/bin/phpunit + +cache: + directories: + - $HOME/.composer/cache + - vendor diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..301f924 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 PHP Middleware + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index c6c0e4a..e3379b2 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,29 @@ # log-http-messages middleware [![Build Status](https://travis-ci.org/php-middleware/log-http-messages.svg)](https://travis-ci.org/php-middleware/log-http-messages) -Middleware for log PSR-7 HTTP messages using PSR-3 logger +PSR-15 middleware for log PSR-7 HTTP messages using PSR-3 logger This middleware provide framework-agnostic possibility to log request and response messages to PSR-3 logger. ## Installation -```json -{ - "require": { - "php-middleware/log-http-messages": "^2.0.0" - } -} +``` +composer require php-middleware/log-http-messages ``` -To log http messages you need pass into `LogRequestMiddleware` implementation of `PhpMiddleware\LogHttpMessages\Formatter\HttpMessagesFormatter`, -instance `Psr\Log\LoggerInterface` and add middleware to your middleware runner. -Third parameter is log level and it's optional (`Psr\Log\LogLevel::INFO` as default). +To log http messages you need pass into `LogRequestMiddleware` implementation of +`PhpMiddleware\LogHttpMessages\Formatter\ServerRequestFormatter`, +`PhpMiddleware\LogHttpMessages\Formatter\ResponseFormatter`, +instance `Psr\Log\LoggerInterface` and add this middleware to your middleware runner. +You can also set log level (`Psr\Log\LogLevel::INFO` as default) and log message (`Request/Response` as default). -There are tree implementation of `PhpMiddleware\LogHttpMessages\Formatter\HttpMessagesFormatter`: +Provided implementation of formatters: -* `PhpMiddleware\LogHttpMessages\Formatter\RequestFormatter` to log request message, -* `PhpMiddleware\LogHttpMessages\Formatter\ResponseFormatter` to log response message, -* `PhpMiddleware\LogHttpMessages\Formatter\BothFormatter` to log request and response message. +* `PhpMiddleware\LogHttpMessages\Formatter\EmptyMessageFormatter`, +* `PhpMiddleware\LogHttpMessages\Formatter\ZendDiactorosToArrayMessageFormatter`, +* `PhpMiddleware\LogHttpMessages\Formatter\ZendDiactorosToStringMessageFormatter`. ```php -$requestFormatter = PhpMiddleware\LogHttpMessages\Formatter\RequestFormatter(); -$responseFormatter = PhpMiddleware\LogHttpMessages\Formatter\ResponseFormatter(); -$formatter = new PhpMiddleware\LogHttpMessages\Formatter\BothFormatter(requestFormatter, responseFormatter); -$logMiddleware = new PhpMiddleware\LogHttpMessages\LogMiddleware(formatter, $logger); +$formatter = PhpMiddleware\LogHttpMessages\Formatter\ZendDiactorosToArrayMessageFormatter(); +$logMiddleware = new PhpMiddleware\LogHttpMessages\LogMiddleware($formatter, $formatter, $logger); $app = new MiddlewareRunner(); $app->add($logMiddleware); @@ -44,4 +40,4 @@ Middleware should works with: * [Slim 3.x](https://github.com/slimphp/Slim) * [zend-log 2.6](https://github.com/zendframework/zend-log) -And any other modern framework [supported middlewares and PSR-7](https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html) and [PSR-3 implementation](http://www.php-fig.org/psr/psr-3/) logger. +And any other modern framework [supported PSR-15 middlewares and PSR-7](https://mwop.net/blog/2015-01-08-on-http-middleware-and-psr-7.html) and [PSR-3 implementation](http://www.php-fig.org/psr/psr-3/) logger. diff --git a/composer.json b/composer.json index dc25ecd..813df82 100644 --- a/composer.json +++ b/composer.json @@ -1,24 +1,27 @@ { "name": "php-middleware/log-http-messages", - "description": "Request and response middleware logger with PSR-7 and PSR-3", + "description": "PSR-15 middleware for log PSR-7 HTTP messages using PSR-3 logger", "type": "library", "keywords": [ "debug", "middleware", "psr", "psr-7", + "psr-15", "log", "logger", "psr-3" ], "require": { - "php": ">=5.5", - "psr/log": "^1.0.0", + "php": ">=7.0", + "psr/log": "^1.0", "psr/http-message": "^1.0", - "zendframework/zend-diactoros": "^1.1.3" + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "zendframework/zend-diactoros": "^1.4 || ^2.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.6" + "phpunit/phpunit": "^6.1" }, "autoload": { "psr-4": { diff --git a/src/Formatter/BothFormatter.php b/src/Formatter/BothFormatter.php deleted file mode 100644 index ab95a2f..0000000 --- a/src/Formatter/BothFormatter.php +++ /dev/null @@ -1,36 +0,0 @@ -requestFormatter = $requestFormatter; - $this->responseFormatter = $responseFormatter; - } - - /** - * @param ServerRequestInterface $request - * @param ResponseInterface $response - * - * @return string - */ - public function format(ServerRequestInterface $request, ResponseInterface $response) - { - $requestString = $this->requestFormatter->format($request, $response); - $reponseString = $this->responseFormatter->format($request, $response); - - return sprintf('Request: %s; Response %s', $requestString, $reponseString); - } -} \ No newline at end of file diff --git a/src/Formatter/EmptyMessageFormatter.php b/src/Formatter/EmptyMessageFormatter.php new file mode 100644 index 0000000..94b13cf --- /dev/null +++ b/src/Formatter/EmptyMessageFormatter.php @@ -0,0 +1,24 @@ +value = $value; + + return $instance; + } + + public static function fromArray(array $value) : self + { + $instance = new self(); + $instance->value = $value; + + return $instance; + } + + public static function createEmpty() : self + { + return new self(); + } + + /** + * @return array|string|null + */ + public function getValue() + { + return $this->value; + } +} diff --git a/src/Formatter/HttpMessagesFormatter.php b/src/Formatter/HttpMessagesFormatter.php deleted file mode 100644 index df21cb1..0000000 --- a/src/Formatter/HttpMessagesFormatter.php +++ /dev/null @@ -1,17 +0,0 @@ -formatter = $formatter; + const LOG_MESSAGE = 'Request/Response'; + + private $logger; + private $level; + private $requestFormatter; + private $responseFormatter; + private $logMessage; + + public function __construct( + ServerRequestFormatter $requestFormatter, + ResponseFormatter $responseFormatter, + Logger $logger, + string $level = LogLevel::INFO, + string $logMessage = self::LOG_MESSAGE + ) { + $this->requestFormatter = $requestFormatter; + $this->responseFormatter = $responseFormatter; $this->logger = $logger; $this->level = $level; + $this->logMessage = $logMessage; } - /** - * @param ServerRequest $request - * @param Response $response - * @param callable $next - * - * @return ResponseInterface - */ - public function __invoke(ServerRequest $request, Response $response, callable $next) + /** @inheritdoc */ + public function process(ServerRequest $request, RequestHandlerInterface $handler): Response { - $outResponse = $next($request, $response); - - $messages = $this->formatter->format($request, $outResponse); + $response = $handler->handle($request); - if (!is_string($messages)) { - throw new \UnexpectedValueException(sprintf('%s must return string', HttpMessagesFormatter::class)); - } + $formattedRequest = $this->requestFormatter->formatServerRequest($request); + $formattedResponse = $this->responseFormatter->formatResponse($response); - $this->logger->log($this->level, $messages); + $this->logger->log($this->level, $this->logMessage, [ + 'request' => $formattedRequest->getValue(), + 'response' => $formattedResponse->getValue(), + ]); - return $outResponse; + return $response; } } diff --git a/test/Formatter/BothFormatterTest.php b/test/Formatter/BothFormatterTest.php deleted file mode 100644 index d112bb3..0000000 --- a/test/Formatter/BothFormatterTest.php +++ /dev/null @@ -1,33 +0,0 @@ -formatter = new BothFormatter($requestFormatter, $responseFormatter); - } - - public function testFormatter() - { - $request = new ServerRequest([], [], 'https://github.com/php-middleware/log-http-messages', 'GET', 'php://input', ['Accept' => 'text/html']); - $response = new Response('php://memory', 500, ['Content-Type' => 'text/html']); - - $result = $this->formatter->format($request, $response); - - $this->assertSame("Request: GET /php-middleware/log-http-messages HTTP/1.1\r\nAccept: text/html; Response HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/html", $result); - } -} \ No newline at end of file diff --git a/test/Formatter/FormattedMessageTest.php b/test/Formatter/FormattedMessageTest.php new file mode 100644 index 0000000..d17bebf --- /dev/null +++ b/test/Formatter/FormattedMessageTest.php @@ -0,0 +1,30 @@ +assertSame('foo', $formattedMessage->getValue()); + } + + public function testCanCreateFromArray() + { + $formattedMessage = FormattedMessage::fromArray(['boo' => 'baz']); + + $this->assertSame(['boo' => 'baz'], $formattedMessage->getValue()); + } + + public function testCanCreateEmpty() + { + $formattedMessage = FormattedMessage::createEmpty(); + + $this->assertNull($formattedMessage->getValue()); + } +} diff --git a/test/Formatter/ZendDiactorosToArrayMessageFormatterTest.php b/test/Formatter/ZendDiactorosToArrayMessageFormatterTest.php new file mode 100644 index 0000000..722ae5d --- /dev/null +++ b/test/Formatter/ZendDiactorosToArrayMessageFormatterTest.php @@ -0,0 +1,31 @@ +formatServerRequest($request); + + $this->assertInternalType('array', $formattedMessage->getValue()); + } + + public function testFormatResponeToArray() + { + $response = new Response(); + $formatter = new ZendDiactorosToArrayMessageFormatter(); + + $formattedMessage = $formatter->formatResponse($response); + + $this->assertInternalType('array', $formattedMessage->getValue()); + } +} diff --git a/test/Formatter/ZendDiactorosToStringMessageFormatterTest.php b/test/Formatter/ZendDiactorosToStringMessageFormatterTest.php new file mode 100644 index 0000000..3c4c511 --- /dev/null +++ b/test/Formatter/ZendDiactorosToStringMessageFormatterTest.php @@ -0,0 +1,31 @@ +formatServerRequest($request); + + $this->assertInternalType('string', $formattedMessage->getValue()); + } + + public function testFormatResponeToArray() + { + $response = new Response(); + $formatter = new ZendDiactorosToStringMessageFormatter(); + + $formattedMessage = $formatter->formatResponse($response); + + $this->assertInternalType('string', $formattedMessage->getValue()); + } +} diff --git a/test/LogMiddlewareTest.php b/test/LogMiddlewareTest.php index f831734..cf0596a 100644 --- a/test/LogMiddlewareTest.php +++ b/test/LogMiddlewareTest.php @@ -2,62 +2,45 @@ namespace PhpMiddlewareTest\LogHttpMessages; -use PhpMiddleware\LogHttpMessages\Formatter\HttpMessagesFormatter; +use PhpMiddleware\LogHttpMessages\Formatter\EmptyMessageFormatter; use PhpMiddleware\LogHttpMessages\LogMiddleware; -use PHPUnit_Framework_TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\RequestHandlerInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -class LogMiddlewareTest extends PHPUnit_Framework_TestCase +class LogMiddlewareTest extends TestCase { - protected $middleware; - protected $formatter; - protected $logger; - protected $request; - protected $response; - protected $next; - protected $level; + /** @var LogMiddleware */ + private $middleware; + /** @var LoggerInterface|MockObject */ + private $logger; + private $handler; protected function setUp() { - $this->request = $this->getMock(ServerRequestInterface::class); - $this->response = $this->getMock(ResponseInterface::class); - $this->nextResponse = clone $this->response; - $this->next = function () { - return $this->nextResponse; - }; - - $this->formatter = $this->getMock(HttpMessagesFormatter::class); - $this->logger = $this->getMock(LoggerInterface::class); - $this->level = LogLevel::ALERT; - - $this->middleware = new LogMiddleware($this->formatter, $this->logger, $this->level); - } + $response = $this->createMock(ResponseInterface::class); - public function testLogMessage() - { - $this->formatter->expects($this->once())->method('format')->with($this->request, $this->nextResponse)->willReturn('boo'); - $this->logger->expects($this->once())->method('log')->with($this->level, 'boo'); + $this->handler = $this->createMock(RequestHandlerInterface::class); + $this->handler->method('handle')->willReturn($response); - $response = $this->executeMiddleware(); + $formatter = new EmptyMessageFormatter(); + $this->logger = $this->createMock(LoggerInterface::class); - $this->assertSame($this->nextResponse, $response); + $this->middleware = new LogMiddleware($formatter, $formatter, $this->logger, LogLevel::ALERT); } - /** - * @expectedException \UnexpectedValueException - */ - public function testTryToLogNullMessage() + public function testLogFormattedMessages() { - $this->formatter->expects($this->once())->method('format')->willReturn(null); + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->createMock(ServerRequestInterface::class); - $this->executeMiddleware(); - } + $this->logger->expects($this->once())->method('log') + ->with(LogLevel::ALERT, LogMiddleware::LOG_MESSAGE, ['request' => null, 'response' => null]); - public function executeMiddleware() - { - return call_user_func($this->middleware, $this->request, $this->response, $this->next); + $this->middleware->process($request, $this->handler); } -} \ No newline at end of file +}