.coveralls.yml 0000666 00000000077 13406430416 0007350 0 ustar 00 service_name: travis-ci
coverage_clover: build/logs/clover.xml
.gitignore 0000666 00000000057 13406430416 0006543 0 ustar 00 /composer.phar
/composer.lock
/vendor/
/build/
.travis.yml 0000666 00000001743 13406430416 0006667 0 ustar 00 language: php
dist: trusty
matrix:
include:
- php: 5.6
env: deps=low
- php: hhvm
env: deps=low
- php: 7.0
env: deps=low
- php: 5.6
- php: hhvm
- php: 7.0
- php: 7.1
- php: 7.2
fast_finish: true
before_install:
- composer config --global --auth github-oauth.github.com $GITHUB_OAUTH_TOKEN
install:
- composer self-update
- if [ "$deps" = "no" ]; then COMPOSER_MEMORY_LIMIT=-1 composer --prefer-stable --no-interaction update; fi;
- if [ "$deps" = "low" ]; then COMPOSER_MEMORY_LIMIT=-1 composer --prefer-lowest --prefer-stable --no-interaction update; fi;
env:
global:
- SYMFONY_DEPRECATIONS_HELPER=strict
- deps=no
script:
- ./vendor/bin/phpunit
- ./vendor/bin/phpcs --standard=PSR2 src/
- ./vendor/bin/phpcpd src/
- ./vendor/bin/phpmd src text cleancode,codesize,controversial,design,naming,unusedcode
after_success:
- travis_retry php vendor/bin/coveralls
cache:
directories:
- vendor
sudo: false
LICENSE 0000666 00000002064 13406430416 0005560 0 ustar 00 Copyright (c) 2015-2017 Nikolay Labinskiy aka e-moe
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.
README.md 0000666 00000010741 13406430416 0006033 0 ustar 00 # Symfony Guzzle6Bundle
[![Latest Stable Version](https://poser.pugx.org/e-moe/guzzle6-bundle/v/stable)](https://packagist.org/packages/e-moe/guzzle6-bundle)
[![Total Downloads](https://poser.pugx.org/e-moe/guzzle6-bundle/downloads)](https://packagist.org/packages/e-moe/guzzle6-bundle)
[![Latest Unstable Version](https://poser.pugx.org/e-moe/guzzle6-bundle/v/unstable)](https://packagist.org/packages/e-moe/guzzle6-bundle)
[![License](https://poser.pugx.org/e-moe/guzzle6-bundle/license)](https://packagist.org/packages/e-moe/guzzle6-bundle)
[![Build Status](https://travis-ci.org/e-moe/guzzle6-bundle.svg?branch=master)](https://travis-ci.org/e-moe/guzzle6-bundle)
[![Coverage Status](https://coveralls.io/repos/e-moe/guzzle6-bundle/badge.svg?branch=master&service=github)](https://coveralls.io/github/e-moe/guzzle6-bundle?branch=master)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/b78325e0-a85f-477a-bd98-13ab1a551742/mini.png)](https://insight.sensiolabs.com/projects/b78325e0-a85f-477a-bd98-13ab1a551742)
This bundle integrates [Guzzle 6.x][guzzle] into Symfony. Guzzle is a PHP framework for building RESTful web service clients.
## Requirements
- PHP 5.6 or above
- Symfony 2.7 or above (including Symfony 3.x, 4.x)
## Installation
To install this bundle, run the command below and you will get the latest version by [Packagist][packagist].
``` bash
composer require e-moe/guzzle6-bundle
```
To use the newest (maybe unstable) version please add following into your composer.json:
``` json
{
"require": {
"e-moe/guzzle6-bundle": "dev-master"
}
}
```
## Usage
Load bundle in AppKernel.php (should be done automatically if you are using Symfony Flex):
``` php
new Emoe\GuzzleBundle\EmoeGuzzleBundle(),
```
Configuration in config.yml (optional):
``` yaml
emoe_guzzle:
log:
enabled: true # Logging requests to Monolog
format: 'Guzzle: [{ts}] "{method} {uri} HTTP/{version}" {code}' # Optional log format customization
```
see more about [log format syntax][log-format].
Using Guzzle in controllers:
``` php
$client = $this->get('guzzle.client');
$response = $client->get('http://example.com');
```
Using Guzzle in your own services:
``` yaml
application.my_service:
class: App\Service\MyService
arguments:
- "@guzzle.client"
```
or you can just use [autowire][autowire] feature with `GuzzleHttp\ClientInterface` type hint.
## Features
### Symfony Debug Profiler
### Symfony Debug Timeline
### Symfony Debug Toolbar
### Symfony Debug Logs (Monolog Integration)
## Suggestions
Adding aliases:
If you want to use different names for provided services you can use aliases. This is a good idea if you don't want
have any dependency to guzzle in your service name.
``` yaml
services:
http.client:
alias: guzzle.client
```
Creating multiple clients:
If you want to have different Guzzle clients in your application all you need is to define them in services file and
add "guzzle.client" tag to turn on Symfony integration (Debug toolbar, logs, so on..).
``` yaml
services:
guzzle.client_one:
class: GuzzleHttp\Client
tags:
- { name: guzzle.client }
guzzle.client_two:
class: GuzzleHttp\Client
tags:
- { name: guzzle.client }
```
## Authors
- Nikolay Labinskiy aka e-moe
Inspired by Chris Wilkinson's and Florian Preusner's GuzzleBundles ([1][misd-guzzle], [2][8p]).
See also the list of [contributors][contributors] who participated in this project.
## License
This bundle is released under the [MIT license](LICENSE)
[guzzle]: http://guzzlephp.org/
[packagist]: https://packagist.org/packages/e-moe/guzzle6-bundle
[autowire]: https://symfony.com/doc/current/service_container.html#the-autowire-option
[contributors]: https://github.com/e-moe/guzzle6-bundle/graphs/contributors
[misd-guzzle]: https://github.com/misd-service-development/guzzle-bundle
[8p]: https://github.com/8p/GuzzleBundle
[log-format]: https://github.com/guzzle/guzzle/blob/master/src/MessageFormatter.php#L12
composer.json 0000666 00000002405 13406430416 0007274 0 ustar 00 {
"name": "e-moe/guzzle6-bundle",
"type": "symfony-bundle",
"description": "Integrates Guzzle 6 into your Symfony application",
"keywords": ["guzzle", "bundle", "http", "http client", "rest", "client", "web service", "curl", "api"],
"homepage": "https://github.com/e-moe/guzzle6-bundle",
"license": "MIT",
"authors": [
{
"name": "Nikolay Labinskiy aka e-moe",
"email": "e-moe@ukr.net"
}
],
"support": {
"issues": "https://github.com/e-moe/guzzle6-bundle/issues"
},
"require": {
"php": ">=5.6",
"symfony/framework-bundle": "^2.7|^3.0|^4.0",
"guzzlehttp/guzzle": "^6.0",
"symfony/stopwatch": "^2.7|^3.0|^4.0"
},
"suggest": {
"symfony/monolog-bundle": "Log requests"
},
"conflict": {
},
"require-dev": {
"phpunit/phpunit": "^5.1",
"symfony/monolog-bundle": "^2.7",
"squizlabs/php_codesniffer": "^2.5",
"phpmd/phpmd": "^2.3",
"sebastian/phpcpd": "^2.0",
"satooshi/php-coveralls": "^2.0"
},
"autoload": {
"psr-4": {
"Emoe\\GuzzleBundle\\": "src"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
}
}
phpunit.xml.dist 0000666 00000001366 13406430416 0007732 0 ustar 00
src/Tests
src
src/Tests
src/DataCollector/GuzzleDataCollector.php 0000666 00000007054 13406430416 0014520 0 ustar 00 logAdapter = $logAdapter;
$this->requestFormatter = $requestFormatter;
$this->responseFormatter = $responseFormatter;
$this->data['requests'] = array();
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
foreach ($this->logAdapter->getLogs() as $log) {
$requestId = spl_object_hash($log['extras']['request']);
if (isset($this->data['requests'][$requestId])) {
continue;
}
/** @var RequestInterface $guzzleRequest */
$guzzleRequest = $log['extras']['request'];
/** @var ResponseInterface $guzzleResponse */
$guzzleResponse = $log['extras']['response'];
$datum['message'] = $log['message'];
$datum['time'] = $log['extras']['time'];
$datum['request'] = $this->requestFormatter->format($guzzleRequest);
$datum['response'] = $this->responseFormatter->format($guzzleRequest, $guzzleResponse);
$datum['is_error'] = $this->isError($guzzleResponse);
$datum['status_code'] = $guzzleResponse->getStatusCode();
$datum['method'] = $guzzleRequest->getMethod();
$this->data['requests'][$requestId] = $datum;
}
}
/**
* @param ResponseInterface $response
* @return bool Returns true if response code is 4xx or 5xx
*/
protected function isError(ResponseInterface $response)
{
return $response->getStatusCode() >= 400 && $response->getStatusCode() < 600;
}
/**
* @return array List of requests with 4xx or 5xx response codes
*/
public function getErrorRequests()
{
return array_filter(
$this->getRequests(),
function ($item) {
return $item['is_error'];
}
);
}
/**
* @return array List of all requests
*/
public function getRequests()
{
return $this->data['requests'];
}
/**
* @return int Total requests duration
*/
public function getTotalDuration()
{
return array_reduce(
$this->getRequests(),
function ($carry, array $request) {
return $carry + $request['time'];
},
0
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'guzzle';
}
/**
* Resets this data collector to its initial state.
*/
public function reset()
{
$this->data['requests'] = array();
}
}
src/DependencyInjection/Compiler/ClientCompilerPass.php 0000666 00000003424 13406430416 0017307 0 ustar 00 findDefinition('emoe_guzzle.handler_stack');
$profilerMiddleware = $container->findDefinition('emoe_guzzle.request_profiler_middleware');
$profilerMiddleware->addMethodCall('attachMiddleware', [$bundleStack]);
$loggerMiddleware = $container->findDefinition('emoe_guzzle.request_logger_middleware');
$loggerMiddleware->addMethodCall('attachMiddleware', [$bundleStack]);
foreach (array_keys($container->findTaggedServiceIds('guzzle.client')) as $id) {
$stack = $bundleStack;
$definition = $container->getDefinition($id);
$arguments = $definition->getArguments();
if (isset($arguments[0]) && is_string($arguments[0])) {
$arguments[0] = $container->getParameter(str_replace('%', '', $arguments[0]));
}
if (isset($arguments[0]['handler'])) {
$stack = $arguments[0]['handler'];
$profilerMiddleware->addMethodCall('attachMiddleware', [$stack]);
$loggerMiddleware->addMethodCall('attachMiddleware', [$stack]);
}
$arguments[0]['handler'] = $stack;
$arguments[0]['profiler_middleware'] = $profilerMiddleware;
$arguments[0]['logger_middleware'] = $loggerMiddleware;
$definition->setArguments($arguments);
}
}
}
src/DependencyInjection/Compiler/MonologCompilerPass.php 0000666 00000002306 13406430416 0017501 0 ustar 00 has('monolog.logger') && $container->getParameter('emoe_guzzle.log.enabled'))) {
return;
}
$bundleStack = $container->findDefinition('emoe_guzzle.handler_stack');
$monologMiddleware = $container->findDefinition('emoe_guzzle.request_monolog_middleware');
$monologMiddleware->addMethodCall('attachMiddleware', [$bundleStack]);
foreach (array_keys($container->findTaggedServiceIds('guzzle.client')) as $id) {
$definition = $container->getDefinition($id);
$arguments = $definition->getArguments();
if (!isset($arguments[0]['handler'])) {
$arguments[0]['handler'] = $bundleStack;
}
$arguments[0]['monolog_middleware'] = $monologMiddleware;
$definition->setArguments($arguments);
}
}
}
src/DependencyInjection/Configuration.php 0000666 00000002516 13406430416 0014605 0 ustar 00 getRootNode();
} else {
// BC layer for symfony/config 4.1 and older
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('emoe_guzzle');
}
$rootNode
->children()
->arrayNode('log')
->canBeDisabled()
->addDefaultsIfNotSet()
->children()
->scalarNode('format')->defaultValue('CLF')->end()
->end()
->end()
->end()
;
return $treeBuilder;
}
}
src/DependencyInjection/EmoeGuzzleExtension.php 0000666 00000002401 13406430416 0015752 0 ustar 00 processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$loader->load('monolog.yml');
$container->setParameter('emoe_guzzle.log.enabled', $config['log']['enabled']);
$logFormat = $config['log']['format'];
if (in_array($logFormat, ['CLF', 'DEBUG', 'SHORT'])) {
$logFormat = constant('GuzzleHttp\\MessageFormatter::'.$logFormat);
}
$container->setParameter('emoe_guzzle.log.format', $logFormat);
}
}
src/EmoeGuzzleBundle.php 0000666 00000001126 13406430416 0011271 0 ustar 00 addCompilerPass(new ClientCompilerPass());
$container->addCompilerPass(new MonologCompilerPass());
}
}
src/Log/AbstractLogAdapter.php 0000666 00000000453 13406430416 0012302 0 ustar 00 log;
}
}
src/Log/ArrayLogAdapter.php 0000666 00000001162 13406430416 0011613 0 ustar 00 logs[] = array('message' => $message, 'priority' => $priority, 'extras' => $extras);
}
/**
* Get logged entries
*
* @return array
*/
public function getLogs()
{
return $this->logs;
}
/**
* Clears logged entries
*/
public function clearLogs()
{
$this->logs = array();
}
}
src/Log/LogAdapterInterface.php 0000666 00000000766 13406430416 0012446 0 ustar 00 Logger::DEBUG,
LOG_INFO => Logger::INFO,
LOG_WARNING => Logger::WARNING,
LOG_ERR => Logger::ERROR,
LOG_CRIT => Logger::CRITICAL,
LOG_ALERT => Logger::ALERT
);
public function __construct(Logger $logObject)
{
$this->log = $logObject;
}
public function log($message, $priority = LOG_INFO, $extras = array())
{
$this->log->addRecord(self::$mapping[$priority], $message, $extras);
}
}
src/Middleware/MiddlewareInterface.php 0000666 00000000510 13406430416 0014020 0 ustar 00 logAdapter = $logAdapter;
$this->stopwatch = $stopwatch;
$this->formatter = $formatter instanceof MessageFormatter ? $formatter : new MessageFormatter($formatter);
}
/**
* @inheritdoc
* @SuppressWarnings(PHPMD.StaticAccess)
*/
public function attachMiddleware(HandlerStack $stack)
{
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$this->onRequestBeforeSend($request);
return $request;
}));
$stack->push(function (callable $handler) {
return function (
RequestInterface $request,
array $options
) use ($handler) {
$promise = $handler($request, $options);
return $promise->then(
function (ResponseInterface $response) use ($request) {
$this->onRequestComplete($request, $response);
return $response;
}
);
};
});
return $stack;
}
/**
* Starts the stopwatch.
*
* @param RequestInterface $request
*/
private function onRequestBeforeSend(RequestInterface $request)
{
$hash = $this->hash($request);
$this->stopwatch->start($hash, self::NAME);
}
/**
* Stops the stopwatch.
*
* @param RequestInterface $request
* @param ResponseInterface $response
*/
private function onRequestComplete(RequestInterface $request, ResponseInterface $response)
{
$hash = $this->hash($request);
// Send the log message to the adapter, adding a category and host
$priority = $response && $this->isError($response) ? LOG_ERR : LOG_DEBUG;
$message = $this->formatter->format($request, $response);
$event = $this->stopwatch->stop($hash);
$this->logAdapter->log($message, $priority, array(
'request' => $request,
'response' => $response,
'time' => $event->getDuration(),
));
}
/**
* @param RequestInterface $request
*
* @return string
*/
private function hash(RequestInterface $request)
{
return spl_object_hash($request);
}
/**
* Checks if HTTP Status code is a Client Error (4xx)
*
* @param ResponseInterface $response
*
* @return bool
*/
public function isClientError(ResponseInterface $response)
{
return $response->getStatusCode() >= 400 && $response->getStatusCode() < 500;
}
/**
* Checks if HTTP Status code is Server OR Client Error (4xx or 5xx)
*
* @param ResponseInterface $response
*
* @return boolean
*/
public function isError(ResponseInterface $response)
{
return $this->isClientError($response) || $this->isServerError($response);
}
/**
* Checks if HTTP Status code is Server Error (5xx)
*
* @param ResponseInterface $response
*
* @return bool
*/
public function isServerError(ResponseInterface $response)
{
return $response->getStatusCode() >= 500 && $response->getStatusCode() < 600;
}
}
src/Middleware/RequestProfilerMiddleware.php 0000666 00000006214 13406430416 0015262 0 ustar 00 stopwatch = $stopwatch;
}
/**
* @inheritdoc
* @SuppressWarnings(PHPMD.StaticAccess)
*/
public function attachMiddleware(HandlerStack $stack)
{
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$this->onRequestBeforeSend($request);
return $request;
}));
$stack->push(function (callable $handler) {
return function (
RequestInterface $request,
array $options
) use ($handler) {
$promise = $handler($request, $options);
return $promise->then(
function (ResponseInterface $response) use ($request) {
$this->onRequestComplete($request);
return $response;
}
);
};
});
return $stack;
}
/**
* Starts the stopwatch.
*
* @param RequestInterface $request
*/
private function onRequestBeforeSend(RequestInterface $request)
{
if (null !== $this->stopwatch) {
$this->start($request);
}
}
/**
* Stops the stopwatch.
*
* @param RequestInterface $request
*/
private function onRequestComplete(RequestInterface $request)
{
if (null !== $this->stopwatch) {
$this->stop($request);
}
}
/**
* @param RequestInterface $request
*/
private function start(RequestInterface $request)
{
$this->requests[$this->hash($request)] = count($this->requests) + 1;
$name = $this->getEventName($request);
$this->stopwatch->start($name, self::NAME);
}
/**
* @param RequestInterface $request
*/
private function stop(RequestInterface $request)
{
$name = $this->getEventName($request);
$this->stopwatch->stop($name);
}
/**
* @param RequestInterface $request
*
* @return string
*/
private function hash(RequestInterface $request)
{
return spl_object_hash($request);
}
/**
* @param RequestInterface $request
*
* @return string
*/
private function getEventName(RequestInterface $request)
{
return sprintf(
'%s: [%d] %s %s',
self::NAME,
$this->requests[$this->hash($request)],
$request->getMethod(),
urldecode((string)$request->getUri())
);
}
}
src/Resources/config/monolog.yml 0000666 00000001170 13406430416 0012753 0 ustar 00 services:
emoe_guzzle.monolog_formatter:
class: 'GuzzleHttp\MessageFormatter'
public: false
arguments:
- '%emoe_guzzle.log.format%'
emoe_guzzle.monolog_log_adapter:
class: 'Emoe\GuzzleBundle\Log\MonologLogAdapter'
public: false
arguments:
- '@monolog.logger'
emoe_guzzle.request_monolog_middleware:
class: 'Emoe\GuzzleBundle\Middleware\RequestLoggerMiddleware'
public: false
arguments:
- '@emoe_guzzle.monolog_log_adapter'
- '@emoe_guzzle.stopwatch'
- '@emoe_guzzle.monolog_formatter'
src/Resources/config/services.yml 0000666 00000003674 13406430416 0013137 0 ustar 00 parameters:
emoe_guzzle.request.format: '{request}'
emoe_guzzle.response.format: '{response}'
services:
emoe_guzzle.handler_stack:
class: 'GuzzleHttp\HandlerStack'
public: false
factory: ['GuzzleHttp\HandlerStack', create]
emoe_guzzle.request_profiler_middleware:
class: 'Emoe\GuzzleBundle\Middleware\RequestProfilerMiddleware'
public: false
arguments:
- '@?debug.stopwatch'
emoe_guzzle.request_logger_middleware:
class: 'Emoe\GuzzleBundle\Middleware\RequestLoggerMiddleware'
public: false
arguments:
- '@emoe_guzzle.log_adapter'
- '@emoe_guzzle.stopwatch'
- '@emoe_guzzle.message_formatter'
emoe_guzzle.stopwatch:
class: 'Symfony\Component\Stopwatch\Stopwatch'
public: false
emoe_guzzle.log_adapter:
class: 'Emoe\GuzzleBundle\Log\ArrayLogAdapter'
public: false
emoe_guzzle.message_formatter:
class: 'GuzzleHttp\MessageFormatter'
public: false
emoe_guzzle.request_formatter:
class: 'GuzzleHttp\MessageFormatter'
public: false
arguments:
- '%emoe_guzzle.request.format%'
emoe_guzzle.response_formatter:
class: 'GuzzleHttp\MessageFormatter'
public: false
arguments:
- '%emoe_guzzle.response.format%'
emoe_guzzle.data_collector:
class: 'Emoe\GuzzleBundle\DataCollector\GuzzleDataCollector'
public: false
arguments:
- '@emoe_guzzle.log_adapter'
- '@emoe_guzzle.request_formatter'
- '@emoe_guzzle.response_formatter'
tags:
- { name: data_collector, template: '@EmoeGuzzle/Collector/guzzle.html.twig', id: 'guzzle' }
guzzle.client:
class: 'GuzzleHttp\Client'
public: true
tags:
- { name: guzzle.client }
GuzzleHttp\ClientInterface:
alias: 'guzzle.client'
src/Resources/doc/img/logs.png 0000666 00000341610 13406430416 0012312 0 ustar 00 PNG
IHDR R sRGB gAMA a pHYs od IDATx^sU%4?33w>3gQZi5VV*~F
hG 7Q(B 5J
7m9
5ؙ|ֵֺkd|{ڽ͵u~qq %A
( h @I@ J P 뮫[XhV 1&kooH V nSr8 rE϶o4 M< {i @QNe<1fKS0' r@_q&B4єi @~O6m
\V)ҥKM;cyd @Nɤ[n曯
Vɠ @L&ĝ