Skip to content

Commit e05e36c

Browse files
committed
feat: adds HttpMethodEnum
1 parent f455e21 commit e05e36c

File tree

3 files changed

+279
-11
lines changed

3 files changed

+279
-11
lines changed

src/Providers/Http/DTO/Request.php

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use InvalidArgumentException;
88
use WordPress\AiClient\Common\AbstractDataTransferObject;
9+
use WordPress\AiClient\Providers\Http\Enums\HttpMethodEnum;
910

1011
/**
1112
* Represents an HTTP request.
@@ -32,9 +33,9 @@ class Request extends AbstractDataTransferObject
3233
public const KEY_BODY = 'body';
3334

3435
/**
35-
* @var string The HTTP method (GET, POST, etc.).
36+
* @var HttpMethodEnum The HTTP method.
3637
*/
37-
protected string $method;
38+
protected HttpMethodEnum $method;
3839

3940
/**
4041
* @var string The request URI.
@@ -56,24 +57,27 @@ class Request extends AbstractDataTransferObject
5657
*
5758
* @since n.e.x.t
5859
*
59-
* @param string $method The HTTP method.
60+
* @param HttpMethodEnum|string $method The HTTP method.
6061
* @param string $uri The request URI.
6162
* @param array<string, string|list<string>> $headers The request headers.
6263
* @param string|null $body The request body.
6364
*
64-
* @throws InvalidArgumentException If the method is empty.
65+
* @throws InvalidArgumentException If the URI is empty or method is invalid.
6566
*/
66-
public function __construct(string $method, string $uri, array $headers = [], ?string $body = null)
67+
public function __construct($method, string $uri, array $headers = [], ?string $body = null)
6768
{
68-
if (empty($method)) {
69-
throw new InvalidArgumentException('HTTP method cannot be empty.');
70-
}
71-
7269
if (empty($uri)) {
7370
throw new InvalidArgumentException('URI cannot be empty.');
7471
}
7572

76-
$this->method = strtoupper($method);
73+
if (is_string($method)) {
74+
$this->method = HttpMethodEnum::from(strtoupper($method));
75+
} elseif ($method instanceof HttpMethodEnum) {
76+
$this->method = $method;
77+
} else {
78+
throw new InvalidArgumentException('Method must be a string or HttpMethodEnum instance.');
79+
}
80+
7781
$this->uri = $uri;
7882
$this->headers = $headers;
7983
$this->body = $body;
@@ -87,6 +91,18 @@ public function __construct(string $method, string $uri, array $headers = [], ?s
8791
* @return string The HTTP method.
8892
*/
8993
public function getMethod(): string
94+
{
95+
return $this->method->value;
96+
}
97+
98+
/**
99+
* Gets the HTTP method enum.
100+
*
101+
* @since n.e.x.t
102+
*
103+
* @return HttpMethodEnum The HTTP method enum.
104+
*/
105+
public function getMethodEnum(): HttpMethodEnum
90106
{
91107
return $this->method;
92108
}
@@ -233,7 +249,7 @@ public static function getJsonSchema(): array
233249
public function toArray(): array
234250
{
235251
$data = [
236-
self::KEY_METHOD => $this->method,
252+
self::KEY_METHOD => $this->method->value,
237253
self::KEY_URI => $this->uri,
238254
self::KEY_HEADERS => $this->headers,
239255
];
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WordPress\AiClient\Providers\Http\Enums;
6+
7+
use WordPress\AiClient\Common\AbstractEnum;
8+
9+
/**
10+
* Represents HTTP request methods.
11+
*
12+
* @since n.e.x.t
13+
*
14+
* @method static self GET()
15+
* @method static self POST()
16+
* @method static self PUT()
17+
* @method static self PATCH()
18+
* @method static self DELETE()
19+
* @method static self HEAD()
20+
* @method static self OPTIONS()
21+
* @method static self CONNECT()
22+
* @method static self TRACE()
23+
*
24+
* @method bool isGet()
25+
* @method bool isPost()
26+
* @method bool isPut()
27+
* @method bool isPatch()
28+
* @method bool isDelete()
29+
* @method bool isHead()
30+
* @method bool isOptions()
31+
* @method bool isConnect()
32+
* @method bool isTrace()
33+
*/
34+
final class HttpMethodEnum extends AbstractEnum
35+
{
36+
/**
37+
* GET method for retrieving resources.
38+
*
39+
* @var string
40+
*/
41+
public const GET = 'GET';
42+
43+
/**
44+
* POST method for creating resources.
45+
*
46+
* @var string
47+
*/
48+
public const POST = 'POST';
49+
50+
/**
51+
* PUT method for updating/replacing resources.
52+
*
53+
* @var string
54+
*/
55+
public const PUT = 'PUT';
56+
57+
/**
58+
* PATCH method for partially updating resources.
59+
*
60+
* @var string
61+
*/
62+
public const PATCH = 'PATCH';
63+
64+
/**
65+
* DELETE method for removing resources.
66+
*
67+
* @var string
68+
*/
69+
public const DELETE = 'DELETE';
70+
71+
/**
72+
* HEAD method for retrieving headers only.
73+
*
74+
* @var string
75+
*/
76+
public const HEAD = 'HEAD';
77+
78+
/**
79+
* OPTIONS method for retrieving allowed methods.
80+
*
81+
* @var string
82+
*/
83+
public const OPTIONS = 'OPTIONS';
84+
85+
/**
86+
* CONNECT method for establishing tunnel.
87+
*
88+
* @var string
89+
*/
90+
public const CONNECT = 'CONNECT';
91+
92+
/**
93+
* TRACE method for diagnostic purposes.
94+
*
95+
* @var string
96+
*/
97+
public const TRACE = 'TRACE';
98+
99+
/**
100+
* Checks if this method is safe (doesn't modify server state).
101+
*
102+
* @since n.e.x.t
103+
*
104+
* @return bool True if the method is safe, false otherwise.
105+
*/
106+
public function isSafe(): bool
107+
{
108+
return in_array($this->value, [self::GET, self::HEAD, self::OPTIONS, self::TRACE], true);
109+
}
110+
111+
/**
112+
* Checks if this method is idempotent.
113+
*
114+
* @since n.e.x.t
115+
*
116+
* @return bool True if the method is idempotent, false otherwise.
117+
*/
118+
public function isIdempotent(): bool
119+
{
120+
return in_array(
121+
$this->value,
122+
[self::GET, self::HEAD, self::OPTIONS, self::TRACE, self::PUT, self::DELETE],
123+
true
124+
);
125+
}
126+
127+
/**
128+
* Checks if this method typically has a request body.
129+
*
130+
* @since n.e.x.t
131+
*
132+
* @return bool True if the method typically has a body, false otherwise.
133+
*/
134+
public function hasBody(): bool
135+
{
136+
return in_array($this->value, [self::POST, self::PUT, self::PATCH], true);
137+
}
138+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WordPress\AiClient\Tests\Unit\Providers\Http\Enums;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use WordPress\AiClient\Providers\Http\Enums\HttpMethodEnum;
9+
use WordPress\AiClient\Tests\traits\EnumTestTrait;
10+
11+
/**
12+
* Tests for the HttpMethodEnum class.
13+
*
14+
* @since n.e.x.t
15+
*
16+
* @covers \WordPress\AiClient\Providers\Http\Enums\HttpMethodEnum
17+
*/
18+
class HttpMethodEnumTest extends TestCase
19+
{
20+
use EnumTestTrait;
21+
22+
/**
23+
* {@inheritDoc}
24+
*
25+
* @since n.e.x.t
26+
*/
27+
protected function getEnumClass(): string
28+
{
29+
return HttpMethodEnum::class;
30+
}
31+
32+
/**
33+
* {@inheritDoc}
34+
*
35+
* @since n.e.x.t
36+
*/
37+
protected function getExpectedValues(): array
38+
{
39+
return [
40+
'GET' => 'GET',
41+
'POST' => 'POST',
42+
'PUT' => 'PUT',
43+
'PATCH' => 'PATCH',
44+
'DELETE' => 'DELETE',
45+
'HEAD' => 'HEAD',
46+
'OPTIONS' => 'OPTIONS',
47+
'CONNECT' => 'CONNECT',
48+
'TRACE' => 'TRACE',
49+
];
50+
}
51+
52+
/**
53+
* Tests that safe methods are correctly identified.
54+
*
55+
* @since n.e.x.t
56+
*
57+
* @return void
58+
*/
59+
public function testIsSafe(): void
60+
{
61+
$this->assertTrue(HttpMethodEnum::GET()->isSafe());
62+
$this->assertTrue(HttpMethodEnum::HEAD()->isSafe());
63+
$this->assertTrue(HttpMethodEnum::OPTIONS()->isSafe());
64+
$this->assertTrue(HttpMethodEnum::TRACE()->isSafe());
65+
66+
$this->assertFalse(HttpMethodEnum::POST()->isSafe());
67+
$this->assertFalse(HttpMethodEnum::PUT()->isSafe());
68+
$this->assertFalse(HttpMethodEnum::PATCH()->isSafe());
69+
$this->assertFalse(HttpMethodEnum::DELETE()->isSafe());
70+
$this->assertFalse(HttpMethodEnum::CONNECT()->isSafe());
71+
}
72+
73+
/**
74+
* Tests that idempotent methods are correctly identified.
75+
*
76+
* @since n.e.x.t
77+
*
78+
* @return void
79+
*/
80+
public function testIsIdempotent(): void
81+
{
82+
$this->assertTrue(HttpMethodEnum::GET()->isIdempotent());
83+
$this->assertTrue(HttpMethodEnum::HEAD()->isIdempotent());
84+
$this->assertTrue(HttpMethodEnum::OPTIONS()->isIdempotent());
85+
$this->assertTrue(HttpMethodEnum::TRACE()->isIdempotent());
86+
$this->assertTrue(HttpMethodEnum::PUT()->isIdempotent());
87+
$this->assertTrue(HttpMethodEnum::DELETE()->isIdempotent());
88+
89+
$this->assertFalse(HttpMethodEnum::POST()->isIdempotent());
90+
$this->assertFalse(HttpMethodEnum::PATCH()->isIdempotent());
91+
$this->assertFalse(HttpMethodEnum::CONNECT()->isIdempotent());
92+
}
93+
94+
/**
95+
* Tests that methods with bodies are correctly identified.
96+
*
97+
* @since n.e.x.t
98+
*
99+
* @return void
100+
*/
101+
public function testHasBody(): void
102+
{
103+
$this->assertTrue(HttpMethodEnum::POST()->hasBody());
104+
$this->assertTrue(HttpMethodEnum::PUT()->hasBody());
105+
$this->assertTrue(HttpMethodEnum::PATCH()->hasBody());
106+
107+
$this->assertFalse(HttpMethodEnum::GET()->hasBody());
108+
$this->assertFalse(HttpMethodEnum::HEAD()->hasBody());
109+
$this->assertFalse(HttpMethodEnum::OPTIONS()->hasBody());
110+
$this->assertFalse(HttpMethodEnum::TRACE()->hasBody());
111+
$this->assertFalse(HttpMethodEnum::DELETE()->hasBody());
112+
$this->assertFalse(HttpMethodEnum::CONNECT()->hasBody());
113+
}
114+
}

0 commit comments

Comments
 (0)