Skip to content

Commit 3b1f332

Browse files
authored
Merge pull request #158 from fbourigault/use-curl-formatter
Add copy as curl button in profiler
2 parents c3cfe86 + 0e8f098 commit 3b1f332

File tree

10 files changed

+144
-14
lines changed

10 files changed

+144
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- The real request method and target url are now displayed in the profiler.
88
- Support the cache plugin configuration for `respect_response_cache_directives`.
99
- Extended WebProfilerToolbar item to list request with details.
10+
- You can now copy any request as cURL command in the profiler.
1011

1112
### Changed
1213

Collector/Formatter.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
use Http\Client\Exception\HttpException;
77
use Http\Client\Exception\TransferException;
88
use Http\Message\Formatter as MessageFormatter;
9+
use Http\Message\Formatter\CurlCommandFormatter;
910
use Psr\Http\Message\RequestInterface;
1011
use Psr\Http\Message\ResponseInterface;
1112

1213
/**
13-
* This class is a decorator for any Http\Message\Formatter with the the ability to format exceptions.
14+
* This class is a decorator for any Http\Message\Formatter with the the ability to format exceptions and requests as
15+
* cURL commands.
1416
*
1517
* @author Fabien Bourigault <bourigaultfabien@gmail.com>
1618
*
@@ -24,11 +26,18 @@ class Formatter implements MessageFormatter
2426
private $formatter;
2527

2628
/**
27-
* @param MessageFormatter $formatter
29+
* @var CurlCommandFormatter
2830
*/
29-
public function __construct(MessageFormatter $formatter)
31+
private $curlFormatter;
32+
33+
/**
34+
* @param MessageFormatter $formatter
35+
* @param CurlCommandFormatter $curlFormatter
36+
*/
37+
public function __construct(MessageFormatter $formatter, CurlCommandFormatter $curlFormatter)
3038
{
3139
$this->formatter = $formatter;
40+
$this->curlFormatter = $curlFormatter;
3241
}
3342

3443
/**
@@ -66,4 +75,16 @@ public function formatResponse(ResponseInterface $response)
6675
{
6776
return $this->formatter->formatResponse($response);
6877
}
78+
79+
/**
80+
* Format a RequestInterface as a cURL command.
81+
*
82+
* @param RequestInterface $request
83+
*
84+
* @return string
85+
*/
86+
public function formatAsCurlCommand(RequestInterface $request)
87+
{
88+
return $this->curlFormatter->formatRequest($request);
89+
}
6990
}

Collector/ProfileClient.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ private function collectRequestInformations(RequestInterface $request, Stack $st
133133
$stack->setRequestScheme($request->getUri()->getScheme());
134134
$stack->setRequestHost($request->getUri()->getHost());
135135
$stack->setClientRequest($this->formatter->formatRequest($request));
136+
$stack->setCurlCommand($this->formatter->formatAsCurlCommand($request));
136137
}
137138

138139
/**

Collector/Stack.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ final class Stack
8181
*/
8282
private $duration = 0;
8383

84+
/**
85+
* @var string
86+
*/
87+
private $curlCommand;
88+
8489
/**
8590
* @param string $client
8691
* @param string $request
@@ -298,4 +303,20 @@ public function setDuration($duration)
298303
{
299304
$this->duration = $duration;
300305
}
306+
307+
/**
308+
* @return string
309+
*/
310+
public function getCurlCommand()
311+
{
312+
return $this->curlCommand;
313+
}
314+
315+
/**
316+
* @param string $curlCommand
317+
*/
318+
public function setCurlCommand($curlCommand)
319+
{
320+
$this->curlCommand = $curlCommand;
321+
}
301322
}

Resources/config/data-collector.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
<service id="httplug.collector.formatter" class="Http\HttplugBundle\Collector\Formatter" public="false">
1212
<argument type="service" id="httplug.formatter.full_http_message"/>
13+
<argument type="service">
14+
<service class="Http\Message\Formatter\CurlCommandFormatter" />
15+
</argument>
1316
</service>
1417

1518
<service id="httplug.collector.collector" class="Http\HttplugBundle\Collector\Collector" public="false">

Resources/public/script/httplug.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,18 @@ document.addEventListener("DOMContentLoaded", function() {
1010
});
1111
});
1212
});
13+
14+
/**
15+
* Copy as cURL.
16+
*/
17+
document.addEventListener("DOMContentLoaded", function () {
18+
Array.prototype.forEach.call(document.getElementsByClassName('httplug-toolbar'), function (toolbar) {
19+
var button = toolbar.querySelector('.httplug-copy-as-curl>button');
20+
button.addEventListener('click', function() {
21+
var input = toolbar.querySelector('.httplug-copy-as-curl>input');
22+
input.select();
23+
document.execCommand('copy');
24+
input.setSelectionRange(0, 0);
25+
});
26+
});
27+
})

Resources/public/style/httplug.css

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,46 @@
2020
text-align: center;
2121
}
2222

23+
/**
24+
* Toolbar
25+
*/
26+
.httplug-toolbar {
27+
display: flex;
28+
justify-content: space-between;
29+
}
30+
31+
.httplug-toolbar>*:not(:last-child) {
32+
margin-right:5px;
33+
}
34+
35+
.httplug-toolbar .httplug-copy-as-curl {
36+
flex: 1;
37+
}
38+
39+
.httplug-copy-as-curl {
40+
font-size: 0; /*hide line return spacings*/
41+
display: flex;
42+
}
43+
44+
.httplug-copy-as-curl>input {
45+
padding: .5em .75em;
46+
border-radius: 2px 0px 0px 2px;
47+
border: 0;
48+
line-height: inherit;
49+
background-color: #eee;
50+
opacity: 1;
51+
font-size: 14px;
52+
flex: 1;
53+
}
54+
55+
.httplug-copy-as-curl>button {
56+
font-size: 14px;
57+
border-radius: 0px 2px 2px 0px;
58+
}
59+
60+
/**
61+
* Message
62+
*/
2363
.httplug-message {
2464
box-sizing: border-box;
2565
padding: 5px;
@@ -29,6 +69,14 @@
2969
white-space: nowrap;
3070
}
3171

72+
.httplug-messages {
73+
clear: both;
74+
display: flex;
75+
}
76+
77+
/**
78+
* Stack header
79+
*/
3280
.httplug-stack-header {
3381
display: flex;
3482
justify-content: space-between;
@@ -58,11 +106,6 @@
58106
font-size: 0; /*hide line return spacings*/
59107
}
60108

61-
.httplug-messages {
62-
clear: both;
63-
display: flex;
64-
}
65-
66109
.httplug-scheme-http {
67110
display: none;
68111
}

Resources/views/webprofiler.html.twig

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,14 @@
105105
</div>
106106
</div>
107107
<div id="httplug-{{ client }}-{{ loop.index }}-details" class="httplug-hidden">
108-
<button data-toggle="#httplug-{{ client }}-{{ loop.index }}-details .httplug-http-body" class="httplug-toggle btn httplug-push-right">Toggle body</button>
108+
<div class="httplug-toolbar">
109+
<div class="httplug-copy-as-curl">
110+
<input readonly="readonly" type="text" value="{{ stack.curlCommand }}" />
111+
<button class="btn tooltip-toggle" aria-label="Copy to clipboard">Copy to clipboard</button>
112+
</div>
113+
<button data-toggle="#httplug-{{ client }}-{{ loop.index }}-stack" class="httplug-toggle btn" >Toggle plugin stack</button>
114+
<button data-toggle="#httplug-{{ client }}-{{ loop.index }}-details .httplug-http-body" class="httplug-toggle btn">Toggle body</button>
115+
</div>
109116
<div class="httplug-messages">
110117
<div class="httplug-message card">
111118
<h4>Request</h4>
@@ -117,9 +124,6 @@
117124
</div>
118125
</div>
119126
{% if stack.profiles %}
120-
<div class="httplug-center">
121-
<button class="btn httplug-toggle" data-toggle="#httplug-{{ client }}-{{ loop.index }}-stack">Toggle plugin stack</button>
122-
</div>
123127
<div id="httplug-{{ client }}-{{ loop.index }}-stack" class="httplug-hidden card">
124128
{% for profile in stack.profiles %}
125129
<h3 class="httplug-plugin-name">{{ profile.plugin }}</h3>

Tests/Unit/Collector/FormatterTest.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Http\Client\Exception\TransferException;
77
use Http\HttplugBundle\Collector\Formatter;
88
use Http\Message\Formatter as MessageFormatter;
9+
use Http\Message\Formatter\CurlCommandFormatter;
910
use Psr\Http\Message\RequestInterface;
1011
use Psr\Http\Message\ResponseInterface;
1112

@@ -16,6 +17,11 @@ class FormatterTest extends \PHPUnit_Framework_TestCase
1617
*/
1718
private $formatter;
1819

20+
/**
21+
* @var MessageFormatter
22+
*/
23+
private $curlFormatter;
24+
1925
/**
2026
* @var Formatter
2127
*/
@@ -24,8 +30,9 @@ class FormatterTest extends \PHPUnit_Framework_TestCase
2430
public function setUp()
2531
{
2632
$this->formatter = $this->getMockBuilder(MessageFormatter::class)->getMock();
33+
$this->curlFormatter = $this->getMockBuilder(CurlCommandFormatter::class)->getMock();
2734

28-
$this->subject = new Formatter($this->formatter);
35+
$this->subject = new Formatter($this->formatter, $this->curlFormatter);
2936
}
3037

3138
public function testFormatRequest()
@@ -88,4 +95,18 @@ public function testFormatException()
8895
$exception = new \RuntimeException('Unexpected error');
8996
$this->assertEquals('Unexpected exception of type "RuntimeException": Unexpected error', $this->subject->formatException($exception));
9097
}
98+
99+
public function testFormatAsCurlCommand()
100+
{
101+
$request = $this->getMockBuilder(RequestInterface::class)->getMock();
102+
103+
$this->curlFormatter
104+
->expects($this->once())
105+
->method('formatRequest')
106+
->with($this->identicalTo($request))
107+
->willReturn('curl -L http://example.com')
108+
;
109+
110+
$this->assertEquals('curl -L http://example.com', $this->subject->formatAsCurlCommand($request));
111+
}
91112
}

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"symfony/options-resolver": "^2.8 || ^3.0",
2727
"symfony/event-dispatcher": "^2.8 || ^3.0",
2828
"symfony/framework-bundle": "^2.8 || ^3.0",
29-
"php-http/message": "^1.3",
29+
"php-http/message": "^1.4",
3030
"php-http/discovery": "^1.0",
3131
"twig/twig": "^1.18 || ^2.0"
3232
},

0 commit comments

Comments
 (0)