Skip to content

Commit 966518e

Browse files
committed
feat: Improve HttpRequestTask. Add request payload and store the response in a property.
1 parent 4f7f121 commit 966518e

File tree

5 files changed

+167
-1
lines changed

5 files changed

+167
-1
lines changed

etc/phing-grammar.rng

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4037,6 +4037,17 @@
40374037
</element>
40384038
</define>
40394039

4040+
<define name="payload">
4041+
<element name="payload">
4042+
<optional>
4043+
<attribute name="trim">
4044+
<data type="boolean"/>
4045+
</attribute>
4046+
</optional>
4047+
<text/>
4048+
</element>
4049+
</define>
4050+
40404051
<define name="hgadd">
40414052
<element name="hgadd">
40424053
<interleave>
@@ -4186,6 +4197,9 @@
41864197
<optional>
41874198
<attribute name="responsecoderegex"/>
41884199
</optional>
4200+
<optional>
4201+
<attribute name="responseproperty"/>
4202+
</optional>
41894203
<optional>
41904204
<attribute name="authuser"/>
41914205
</optional>
@@ -4215,6 +4229,9 @@
42154229
<zeroOrMore>
42164230
<ref name="postparameter"/>
42174231
</zeroOrMore>
4232+
<optional>
4233+
<ref name="payload"/>
4234+
</optional>
42184235
</interleave>
42194236
</element>
42204237
</define>

src/Phing/Task/Ext/Http/HttpRequestTask.php

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
use GuzzleHttp\Middleware;
2424
use Phing\Exception\BuildException;
25+
use Phing\Project;
2526
use Phing\Type\Parameter;
27+
use Phing\Type\Payload;
2628
use Phing\Util\Regexp;
2729
use Phing\Util\RegexpException;
2830
use Phing\Util\StringHelper;
@@ -74,6 +76,16 @@ class HttpRequestTask extends HttpTask
7476
*/
7577
private $regexp;
7678

79+
/**
80+
* The property where the http response is stored.
81+
*/
82+
private string $responseProperty = '';
83+
84+
/**
85+
* Payload to send as request body.
86+
*/
87+
private ?Payload $payload = null;
88+
7789
/**
7890
* Sets the response regex
7991
*
@@ -94,6 +106,14 @@ public function setResponseCodeRegex($regex)
94106
$this->responseCodeRegex = $regex;
95107
}
96108

109+
/**
110+
* Set the name of the property where the HTTP response is stored.
111+
*/
112+
public function setResponseProperty(string $property): void
113+
{
114+
$this->responseProperty = $property;
115+
}
116+
97117
/**
98118
* Sets whether to enable detailed logging
99119
*
@@ -126,6 +146,15 @@ public function createPostParameter()
126146
return $this->postParameters[$num - 1];
127147
}
128148

149+
/**
150+
* Creates the body of the current request.
151+
*/
152+
public function createPayload(): Payload
153+
{
154+
$this->payload = new Payload();
155+
return $this->payload;
156+
}
157+
129158
/**
130159
* Load the necessary environment for running this task.
131160
*
@@ -146,7 +175,16 @@ public function init()
146175
*/
147176
protected function request($options = [])
148177
{
149-
if ($this->method === 'POST') {
178+
$hasPostParameters = \count($this->postParameters) > 0;
179+
$hasPayload = $this->payload instanceof Payload;
180+
181+
if ($hasPostParameters && $hasPayload) {
182+
$message = 'Cannot use <postparameter/> and <payload/> simultaneously.';
183+
$this->log($message, Project::MSG_ERR);
184+
throw new BuildException($message);
185+
}
186+
187+
if ($hasPostParameters && $this->method === 'POST') {
150188
$idx = ($this->isHeaderSet('content-type', 'application/json') ? 'json' : 'form_params');
151189
$options[$idx] = array_reduce(
152190
$this->postParameters,
@@ -157,6 +195,12 @@ function ($carry, Parameter $postParameter) {
157195
);
158196
}
159197

198+
if ($hasPayload) {
199+
// Guzzle: the "body" option cannot be used with "form_params", "multipart", or "json".
200+
unset($options['form_params'], $options['multipart'], $options['json']);
201+
$options['body'] = $this->payload->getText();
202+
}
203+
160204
if ($this->verbose) {
161205
self::getHandlerStack()->push(Middleware::log(new ConsoleLogger(new ConsoleOutput()), new \GuzzleHttp\MessageFormatter()));
162206
}
@@ -205,5 +249,10 @@ protected function processResponse(ResponseInterface $response)
205249

206250
$this->log('The response status-code matched the provided regex.');
207251
}
252+
253+
if ($this->responseProperty !== '') {
254+
$this->getProject()->setNewProperty($this->responseProperty, $response->getBody());
255+
$this->log("Saving response into '{$this->responseProperty}' property.");
256+
}
208257
}
209258
}

src/Phing/Type/Payload.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phing\Type;
6+
7+
class Payload
8+
{
9+
private string $text = '';
10+
private bool $trim = true;
11+
12+
public function addText(string $text): void
13+
{
14+
$this->text = $text;
15+
}
16+
17+
public function setTrim(bool $trim): void
18+
{
19+
$this->trim = $trim;
20+
}
21+
22+
public function getText(): string
23+
{
24+
return $this->trim ? \trim($this->text) : $this->text;
25+
}
26+
}

tests/Phing/Test/Task/Ext/Http/HttpRequestTaskTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
use GuzzleHttp\Psr7\Response;
2424
use Phing\Exception\BuildException;
25+
use Phing\Project;
2526

2627
/**
2728
* @author Alexey Borzov <avb@php.net>
@@ -118,6 +119,45 @@ public function testConfigurationViaProperties(): void
118119
$this->assertEquals($options['timeout'], $this->traces[0]['options']['timeout']);
119120
}
120121

122+
public function testPayloadOrPostParameters(): void
123+
{
124+
$this->expectBuildException(__FUNCTION__, 'Cannot use <postparameter/> and <payload/> simultaneously.');
125+
$this->assertInLogs('Cannot use <postparameter/> and <payload/> simultaneously.', Project::MSG_ERR);
126+
}
127+
128+
public function testPayload(): void
129+
{
130+
$this->createRequestWithMockAdapter();
131+
$this->executeTarget(__FUNCTION__);
132+
/** @var \GuzzleHttp\Psr7\Stream $body */
133+
$body = $this->traces[0]['request']->getBody();
134+
$this->assertSame('{"email": "foo@example.com"}', $body->getContents());
135+
}
136+
137+
public function testPayloadNoTrim(): void
138+
{
139+
$this->createRequestWithMockAdapter();
140+
$this->executeTarget(__FUNCTION__);
141+
/** @var \GuzzleHttp\Psr7\Stream $body */
142+
$body = $this->traces[0]['request']->getBody();
143+
$this->assertSame("\n 19de4dd8-d46b-11f0-a654-d778f66caf95\n ", $body->getContents());
144+
}
145+
146+
public function testResponseProperty(): void
147+
{
148+
$this->createRequestWithMockAdapter();
149+
$this->executeTarget(__FUNCTION__);
150+
$this->assertPropertyEquals('example.response', "The response containing a 'foo' string");
151+
$this->assertInLogs("The response containing a 'foo' string");
152+
}
153+
154+
public function testExistentProperty(): void
155+
{
156+
$this->createRequestWithMockAdapter();
157+
$this->executeTarget(__FUNCTION__);
158+
$this->assertPropertyEquals('existent.property', '2bf39066-d46e-11f0-8c1a-9795b4c58881');
159+
}
160+
121161
protected function createRequestWithMockAdapter(): void
122162
{
123163
$this->createMockHandler([

tests/etc/tasks/ext/http/httprequest.xml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,38 @@
4343
<property name="phing.http.timeout" value="20" />
4444
<http-request url="http://example.com/foo.bar" />
4545
</target>
46+
47+
<target name="testPayloadOrPostParameters">
48+
<http-request url="http://example.com/post" method="POST">
49+
<postparameter name="username" value="foo"/>
50+
<payload>bar</payload>
51+
</http-request>
52+
</target>
53+
54+
<target name="testPayload">
55+
<http-request url="http://example.com/post" method="POST">
56+
<payload>
57+
{"email": "foo@example.com"}
58+
</payload>
59+
</http-request>
60+
</target>
61+
62+
<target name="testPayloadNoTrim">
63+
<http-request url="http://example.com/post" method="POST">
64+
<payload trim="false">
65+
19de4dd8-d46b-11f0-a654-d778f66caf95
66+
</payload>
67+
</http-request>
68+
</target>
69+
70+
<target name="testResponseProperty">
71+
<http-request url="http://example.com/get" method="GET" responseProperty="example.response"/>
72+
<echo>${example.response}</echo>
73+
</target>
74+
75+
<target name="testExistentProperty">
76+
<property name="existent.property" value="2bf39066-d46e-11f0-8c1a-9795b4c58881"/>
77+
<http-request url="http://example.com/get" method="GET" responseProperty="existent.property"/>
78+
</target>
79+
4680
</project>

0 commit comments

Comments
 (0)