Skip to content

Commit 8389cae

Browse files
committed
support swoole driver
1 parent 14be802 commit 8389cae

8 files changed

Lines changed: 144 additions & 244 deletions

File tree

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
],
2222
"require": {
2323
"php": ">=8.0",
24-
"nyholm/psr7": "^1.8",
24+
"guzzlehttp/psr7": "^2.6",
2525
"league/container": "^4.0",
2626
"league/route": "^5.0",
2727
"illuminate/database": "^9.0",
@@ -30,6 +30,7 @@
3030
"respect/validation": "^2.2",
3131
"symfony/finder": "^6",
3232
"guzzlehttp/guzzle": "^7.7",
33-
"symfony/dotenv": "^6.0"
33+
"symfony/dotenv": "^6.0",
34+
"ext-simplexml": "*"
3435
}
3536
}

src/Commands/StartCommand.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
3232
return match ($serverConfig->getDriver()) {
3333
Driver::WORKERMAN => $this->workermanStart(),
3434
Driver::ROADRUNNER => $this->roadrunnerStart($output, $serverConfig),
35+
Driver::SWOOLE => $this->swooleStart(),
3536
default => throw new RuntimeException('unsupported driver: ' . $serverConfig->getDriver()),
3637
};
3738
}
@@ -78,4 +79,16 @@ private function workermanStart(): int
7879

7980
return Command::SUCCESS;
8081
}
82+
83+
/**
84+
* @throws ContainerExceptionInterface
85+
* @throws ReflectionException
86+
* @throws NotFoundExceptionInterface
87+
*/
88+
private function swooleStart(): int
89+
{
90+
Application::getClass(Application::class)->run();
91+
92+
return Command::SUCCESS;
93+
}
8194
}

src/Http/Enum/Driver.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ class Driver
99
public const WORKERMAN = 'workerman';
1010

1111
public const ROADRUNNER = 'roadrunner';
12+
13+
public const SWOOLE = 'swoole';
1214
}

src/Http/Response.php

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,8 @@
44

55
namespace MicroPHP\Framework\Http;
66

7-
use MicroPHP\Framework\Http\Traits\MessageTrait;
87
use Psr\Http\Message\ResponseInterface;
98

10-
class Response implements ResponseInterface
9+
class Response extends \GuzzleHttp\Psr7\Response implements ResponseInterface
1110
{
12-
use MessageTrait;
13-
14-
private ResponseInterface $bind;
15-
16-
public function __construct(int $status = 200, array $headers = [], $body = null, string $version = '1.1', string $reason = null)
17-
{
18-
$this->bind = new \Nyholm\Psr7\Response($status, $headers, $body, $version, $reason);
19-
}
20-
21-
public function getStatusCode(): int
22-
{
23-
return $this->bind->getStatusCode();
24-
}
25-
26-
public function withStatus(int $code, string $reasonPhrase = ''): void
27-
{
28-
$this->bind->withStatus($code, $reasonPhrase);
29-
}
30-
31-
public function getReasonPhrase(): string
32-
{
33-
return $this->bind->getReasonPhrase();
34-
}
35-
36-
public function getProtocolVersion(): string
37-
{
38-
return $this->bind->getProtocolVersion();
39-
}
4011
}

src/Http/ServerFactory.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use MicroPHP\Framework\Http\Contract\HttpServerInterface;
99
use MicroPHP\Framework\Http\Enum\Driver;
1010
use MicroPHP\RoadRunner\RoadRunnerHttpServer;
11+
use MicroPHP\Swoole\SwooleHttpServer;
1112
use MicroPHP\Workerman\WorkermanHttpServer;
1213
use RuntimeException;
1314

@@ -19,6 +20,7 @@ public static function newServer(): HttpServerInterface
1920
return match ($serverConfig->getDriver()) {
2021
Driver::WORKERMAN => new WorkermanHttpServer(),
2122
Driver::ROADRUNNER => new RoadRunnerHttpServer(),
23+
Driver::SWOOLE => new SwooleHttpServer(),
2224
default => throw new RuntimeException('unsupported driver: ' . $serverConfig->getDriver()),
2325
};
2426
}

src/Http/ServerRequest.php

Lines changed: 122 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -4,152 +4,137 @@
44

55
namespace MicroPHP\Framework\Http;
66

7+
use GuzzleHttp\Psr7\HttpFactory;
8+
use GuzzleHttp\Psr7\Uri;
9+
use InvalidArgumentException;
710
use MicroPHP\Framework\Http\Traits\InputTrait;
8-
use MicroPHP\Framework\Http\Traits\MessageTrait;
11+
use Psr\Http\Message\RequestInterface;
912
use Psr\Http\Message\ServerRequestInterface;
1013
use Psr\Http\Message\UriInterface;
14+
use Swoole\Http\Request;
1115

12-
class ServerRequest implements ServerRequestInterface
16+
class ServerRequest extends \GuzzleHttp\Psr7\ServerRequest implements ServerRequestInterface
1317
{
14-
use MessageTrait;
1518
use InputTrait;
1619

1720
private ServerRequestInterface $bind;
1821

19-
public function __construct(string $method, $uri, array $headers = [], $body = null, string $version = '1.1', array $serverParams = [])
22+
public static function fromPsr7(ServerRequestInterface $request): ServerRequestInterface|ServerRequest
2023
{
21-
$this->bind = new \Nyholm\Psr7\ServerRequest($method, $uri, $headers, $body, $version, $serverParams);
22-
}
23-
24-
public static function fromPsr7(ServerRequestInterface $request): static
25-
{
26-
return new static($request->getMethod(), $request->getUri(), $request->getHeaders(), $request->getBody(), $request->getProtocolVersion(), $request->getServerParams());
27-
}
28-
29-
public function getServerParams(): array
30-
{
31-
return $this->bind->getServerParams();
32-
}
33-
34-
public function getCookieParams(): array
35-
{
36-
return $this->bind->getCookieParams();
37-
}
38-
39-
public function withCookieParams(array $cookies): static
40-
{
41-
$new = clone $this;
42-
$new->bind = $this->bind->withCookieParams($cookies);
43-
44-
return $new;
45-
}
46-
47-
public function getQueryParams(): array
48-
{
49-
return $this->bind->getQueryParams();
50-
}
51-
52-
public function withQueryParams(array $query): static
53-
{
54-
$new = clone $this;
55-
$new->bind = $this->bind->withQueryParams($query);
56-
57-
return $new;
58-
}
59-
60-
public function getUploadedFiles(): array
61-
{
62-
return $this->bind->getUploadedFiles();
63-
}
64-
65-
public function withUploadedFiles(array $uploadedFiles): static
66-
{
67-
$new = clone $this;
68-
$new->bind = $this->bind->withUploadedFiles($uploadedFiles);
69-
70-
return $new;
71-
}
72-
73-
public function getParsedBody(): object|array|null
74-
{
75-
return $this->bind->getParsedBody();
76-
}
77-
78-
public function withParsedBody($data): static
79-
{
80-
$new = clone $this;
81-
$new->bind = $this->bind->withParsedBody($data);
82-
83-
return $new;
84-
}
85-
86-
public function getAttributes(): array
87-
{
88-
return $this->bind->getAttributes();
89-
}
90-
91-
public function getAttribute(string $name, $default = null)
92-
{
93-
return $this->bind->getAttribute($name, $default);
94-
}
95-
96-
public function withAttribute(string $name, $value): static
97-
{
98-
$new = clone $this;
99-
$new->bind = $this->bind->withAttribute($name, $value);
100-
101-
return $new;
102-
}
103-
104-
public function withoutAttribute(string $name): static
105-
{
106-
$new = clone $this;
107-
$new->bind = $this->bind->withoutAttribute($name);
108-
109-
return $new;
110-
}
111-
112-
public function getRequestTarget(): string
113-
{
114-
return $this->bind->getRequestTarget();
115-
}
116-
117-
public function withRequestTarget(string $requestTarget): static
118-
{
119-
$new = clone $this;
120-
$new->bind = $this->bind->withRequestTarget($requestTarget);
121-
122-
return $new;
123-
}
124-
125-
public function getMethod(): string
126-
{
127-
return $this->bind->getMethod();
128-
}
129-
130-
public function withMethod(string $method): static
131-
{
132-
$new = clone $this;
133-
$new->bind = $this->bind->withMethod($method);
134-
135-
return $new;
136-
}
137-
138-
public function getUri(): UriInterface
139-
{
140-
return $this->bind->getUri();
141-
}
142-
143-
public function withUri(UriInterface $uri, bool $preserveHost = false): static
144-
{
145-
$new = clone $this;
146-
$new->bind = $this->bind->withUri($uri, $preserveHost);
147-
148-
return $new;
149-
}
150-
151-
public function getProtocolVersion(): string
152-
{
153-
return $this->bind->getProtocolVersion();
24+
return (new static($request->getMethod(), $request->getUri(), $request->getHeaders(), $request->getBody(), $request->getProtocolVersion(), $request->getServerParams()))
25+
->withParsedBody(self::normalizeParsedBody($request->getParsedBody(), $request))
26+
->withUploadedFiles($request->getUploadedFiles())
27+
->withCookieParams($request->getCookieParams())
28+
->withQueryParams($request->getQueryParams());
29+
}
30+
31+
public static function fromSwoole(Request $swooleRequest): ServerRequestInterface|ServerRequest
32+
{
33+
$server = $swooleRequest->server;
34+
$method = $server['request_method'] ?? 'GET';
35+
$headers = $swooleRequest->header ?? [];
36+
$uri = self::getUriFromSwooleRequest($swooleRequest);
37+
$httpFactory = new HttpFactory();
38+
$body = $httpFactory->createStream((string) $swooleRequest->rawContent());
39+
$protocol = isset($server['server_protocol']) ? str_replace('HTTP/', '', $server['server_protocol']) : '1.1';
40+
$request = new ServerRequest($method, $uri, $headers, $body, $protocol, $server);
41+
return $request->withCookieParams($swooleRequest->cookie ?? [])
42+
->withQueryParams($swooleRequest->get ?? [])
43+
->withParsedBody(self::normalizeParsedBody($swooleRequest->post ?? [], $request))
44+
->withUploadedFiles(self::normalizeFiles($swooleRequest->files ?? []));
45+
}
46+
47+
private static function getUriFromSwooleRequest(Request $swooleRequest): UriInterface
48+
{
49+
$server = $swooleRequest->server;
50+
$header = $swooleRequest->header;
51+
$uri = new Uri();
52+
$uri = $uri->withScheme(! empty($server['https']) && $server['https'] !== 'off' ? 'https' : 'http');
53+
54+
$hasPort = false;
55+
if (isset($server['http_host'])) {
56+
[$host, $port] = self::parseHost($server['http_host']);
57+
$uri = $uri->withHost($host);
58+
if (isset($port)) {
59+
$hasPort = true;
60+
$uri = $uri->withPort($port);
61+
}
62+
} elseif (isset($server['server_name'])) {
63+
$uri = $uri->withHost($server['server_name']);
64+
} elseif (isset($server['server_addr'])) {
65+
$uri = $uri->withHost($server['server_addr']);
66+
} elseif (isset($header['host'])) {
67+
$hasPort = true;
68+
[$host, $port] = self::parseHost($header['host']);
69+
if (isset($port) && $port !== self::getUriDefaultPort($uri)) {
70+
$uri = $uri->withPort($port);
71+
}
72+
73+
$uri = $uri->withHost($host);
74+
}
75+
76+
if (! $hasPort && isset($server['server_port'])) {
77+
$uri = $uri->withPort($server['server_port']);
78+
}
79+
80+
$hasQuery = false;
81+
if (isset($server['request_uri'])) {
82+
$requestUriParts = explode('?', $server['request_uri']);
83+
$uri = $uri->withPath($requestUriParts[0]);
84+
if (isset($requestUriParts[1])) {
85+
$hasQuery = true;
86+
$uri = $uri->withQuery($requestUriParts[1]);
87+
}
88+
}
89+
90+
if (! $hasQuery && isset($server['query_string'])) {
91+
$uri = $uri->withQuery($server['query_string']);
92+
}
93+
94+
return $uri;
95+
}
96+
97+
/**
98+
* Get host parts, support ipv6.
99+
*/
100+
private static function parseHost(string $httpHost): array
101+
{
102+
$parts = parse_url('//' . $httpHost);
103+
if (! isset($parts['host'])) {
104+
throw new InvalidArgumentException('Invalid host: ' . $httpHost);
105+
}
106+
107+
return [$parts['host'], $parts['port'] ?? null];
108+
}
109+
110+
private static function getUriDefaultPort(UriInterface $uri): ?int
111+
{
112+
return $uri->getScheme() === 'https' ? 443 : ($uri->getScheme() === 'http' ? 80 : null);
113+
}
114+
115+
protected static function normalizeParsedBody(array $data = [], ?RequestInterface $request = null): array
116+
{
117+
if (! $request) {
118+
return $data;
119+
}
120+
121+
$rawContentType = $request->getHeaderLine('content-type');
122+
if (($pos = strpos($rawContentType, ';')) !== false) {
123+
$contentType = strtolower(substr($rawContentType, 0, $pos));
124+
} else {
125+
$contentType = strtolower($rawContentType);
126+
}
127+
switch ($contentType) {
128+
case 'application/json':
129+
case 'text/json':
130+
$data = json_decode((string) $request->getBody(), true);
131+
break;
132+
case 'application/xml':
133+
case 'text/xml':
134+
$data = (array) simplexml_load_string((string) $request->getBody());
135+
break;
136+
}
137+
138+
return $data;
154139
}
155140
}

0 commit comments

Comments
 (0)