This commit is contained in:
2023-04-15 23:31:16 +08:00
parent 2d9ac93a7a
commit 41a53200b3
69 changed files with 1678 additions and 749 deletions
+70 -16
View File
@@ -1,13 +1,32 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use InvalidArgumentException;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;
class Message implements MessageInterface
{
/**
* @var string
*/
private string $version = '1.1';
/**
* @var array
*/
private array $headers = [];
/**
* @var StreamInterface
*/
private StreamInterface $stream;
/**
* Retrieves the HTTP protocol version as a string.
*
@@ -15,9 +34,10 @@ class Message implements MessageInterface
*
* @return string HTTP protocol version.
*/
public function getProtocolVersion()
public function getProtocolVersion(): string
{
// TODO: Implement getProtocolVersion() method.
return $this->version;
}
/**
@@ -33,9 +53,11 @@ class Message implements MessageInterface
* @param string $version HTTP protocol version
* @return static
*/
public function withProtocolVersion(string $version)
public function withProtocolVersion(string $version): static
{
// TODO: Implement withProtocolVersion() method.
$this->version = $version;
return $this;
}
/**
@@ -63,9 +85,10 @@ class Message implements MessageInterface
* key MUST be a header name, and each value MUST be an array of strings
* for that header.
*/
public function getHeaders()
public function getHeaders(): array
{
// TODO: Implement getHeaders() method.
return $this->headers;
}
/**
@@ -76,9 +99,10 @@ class Message implements MessageInterface
* name using a case-insensitive string comparison. Returns false if
* no matching header name is found in the message.
*/
public function hasHeader(string $name)
public function hasHeader(string $name): bool
{
// TODO: Implement hasHeader() method.
return isset($this->headers[$name]) && $this->headers[$name] !== null;
}
/**
@@ -95,9 +119,15 @@ class Message implements MessageInterface
* header. If the header does not appear in the message, this method MUST
* return an empty array.
*/
public function getHeader(string $name)
public function getHeader(string $name): array
{
// TODO: Implement getHeader() method.
if (isset($this->headers[$name])) {
$header = $this->headers[$name];
return is_string($header) ? [$header] : $header;
}
return [];
}
/**
@@ -119,9 +149,24 @@ class Message implements MessageInterface
* concatenated together using a comma. If the header does not appear in
* the message, this method MUST return an empty string.
*/
public function getHeaderLine(string $name)
public function getHeaderLine(string $name): string
{
// TODO: Implement getHeaderLine() method.
return implode(';', $this->getHeader($name));
}
/**
* @param string $name
* @param string|null $default
* @return string|null
*/
public function header(string $name, ?string $default = null): ?string
{
if (!$this->hasHeader($name)) {
return $default;
}
return $this->getHeaderLine($name);
}
/**
@@ -137,11 +182,13 @@ class Message implements MessageInterface
* @param string $name Case-insensitive header field name.
* @param string|string[] $value Header value(s).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
* @throws InvalidArgumentException for invalid header names or values.
*/
public function withHeader(string $name, $value)
public function withHeader(string $name, $value): static
{
// TODO: Implement withHeader() method.
// TODO: Implement withAddedHeader() method.
$this->headers[$name] = $value;
return $this;
}
/**
@@ -158,11 +205,13 @@ class Message implements MessageInterface
* @param string $name Case-insensitive header field name to add.
* @param string|string[] $value Header value(s).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
* @throws InvalidArgumentException for invalid header names or values.
*/
public function withAddedHeader(string $name, $value)
public function withAddedHeader(string $name, $value): static
{
// TODO: Implement withAddedHeader() method.
$this->headers[$name] = $value;
return $this;
}
/**
@@ -177,9 +226,11 @@ class Message implements MessageInterface
* @param string $name Case-insensitive header field name to remove.
* @return static
*/
public function withoutHeader(string $name)
public function withoutHeader(string $name): static
{
// TODO: Implement withoutHeader() method.
unset($this->headers[$name]);
return $this;
}
/**
@@ -187,9 +238,10 @@ class Message implements MessageInterface
*
* @return StreamInterface Returns the body as a stream.
*/
public function getBody()
public function getBody(): StreamInterface
{
// TODO: Implement getBody() method.
return $this->stream;
}
/**
@@ -203,10 +255,12 @@ class Message implements MessageInterface
*
* @param StreamInterface $body Body.
* @return static
* @throws \InvalidArgumentException When the body is not valid.
* @throws InvalidArgumentException When the body is not valid.
*/
public function withBody(StreamInterface $body)
public function withBody(StreamInterface $body): static
{
// TODO: Implement withBody() method.
$this->stream = $body;
return $this;
}
}
+41 -7
View File
@@ -1,6 +1,6 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\UriInterface;
@@ -8,6 +8,19 @@ use Psr\Http\Message\UriInterface;
class Request extends Message implements RequestInterface
{
/**
* @var string
*/
private string $method;
/**
* @var UriInterface
*/
private UriInterface $uri;
/**
* Retrieves the message's request target.
*
@@ -24,9 +37,23 @@ class Request extends Message implements RequestInterface
*
* @return string
*/
public function getRequestTarget()
public function getRequestTarget(): string
{
// TODO: Implement getRequestTarget() method.
return (string)$this->getUri();
}
/**
* @param array $headers
* @return $this
*/
public function withHeaders(array $headers): static
{
foreach ($headers as $key => $header) {
$this->withHeader($key, [$header]);
}
return $this;
}
/**
@@ -46,9 +73,10 @@ class Request extends Message implements RequestInterface
* @param string $requestTarget
* @return static
*/
public function withRequestTarget(string $requestTarget)
public function withRequestTarget(string $requestTarget): static
{
// TODO: Implement withRequestTarget() method.
return $this;
}
/**
@@ -56,9 +84,10 @@ class Request extends Message implements RequestInterface
*
* @return string Returns the request method.
*/
public function getMethod()
public function getMethod(): string
{
// TODO: Implement getMethod() method.
return $this->method;
}
/**
@@ -76,9 +105,11 @@ class Request extends Message implements RequestInterface
* @return static
* @throws \InvalidArgumentException for invalid HTTP methods.
*/
public function withMethod(string $method)
public function withMethod(string $method): static
{
// TODO: Implement withMethod() method.
$this->method = $method;
return $this;
}
/**
@@ -90,9 +121,10 @@ class Request extends Message implements RequestInterface
* @return UriInterface Returns a UriInterface instance
* representing the URI of the request.
*/
public function getUri()
public function getUri(): UriInterface
{
// TODO: Implement getUri() method.
return $this->uri;
}
/**
@@ -125,8 +157,10 @@ class Request extends Message implements RequestInterface
* @param bool $preserveHost Preserve the original state of the Host header.
* @return static
*/
public function withUri(UriInterface $uri, bool $preserveHost = false)
public function withUri(UriInterface $uri, bool $preserveHost = false): static
{
// TODO: Implement withUri() method.
$this->uri = $uri;
return $this;
}
}
+27 -4
View File
@@ -1,12 +1,30 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use Kiri\Router\ContentType;
use Psr\Http\Message\ResponseInterface;
class Response extends Message implements ResponseInterface
{
private int $code = 200;
private string $reasonPhrase;
/**
* @param ContentType $type
* @return $this
*/
public function withContentType(ContentType $type): static
{
$this->withHeader('Content-Type', $type->name);
return $this;
}
/**
* Gets the response status code.
*
@@ -15,9 +33,10 @@ class Response extends Message implements ResponseInterface
*
* @return int Status code.
*/
public function getStatusCode()
public function getStatusCode(): int
{
// TODO: Implement getStatusCode() method.
return $this->code;
}
/**
@@ -40,9 +59,12 @@ class Response extends Message implements ResponseInterface
* @return static
* @throws \InvalidArgumentException For invalid status code arguments.
*/
public function withStatus(int $code, string $reasonPhrase = '')
public function withStatus(int $code, string $reasonPhrase = ''): static
{
// TODO: Implement withStatus() method.
$this->code = $code;
$this->reasonPhrase = $reasonPhrase;
return $this;
}
/**
@@ -58,8 +80,9 @@ class Response extends Message implements ResponseInterface
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
* @return string Reason phrase; must return an empty string if none present.
*/
public function getReasonPhrase()
public function getReasonPhrase(): string
{
// TODO: Implement getReasonPhrase() method.
return $this->reasonPhrase;
}
}
+60 -29
View File
@@ -1,12 +1,24 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use Psr\Http\Message\ServerRequestInterface;
class ServerRequest extends Request implements ServerRequestInterface
{
private array $posts = [];
private array $query = [];
private array $cookies = [];
private array $server = [];
private array $files = [];
/**
* Retrieve server parameters.
*
@@ -16,9 +28,10 @@ class ServerRequest extends Request implements ServerRequestInterface
*
* @return array
*/
public function getServerParams()
public function getServerParams(): array
{
// TODO: Implement getServerParams() method.
return $this->server;
}
/**
@@ -31,9 +44,10 @@ class ServerRequest extends Request implements ServerRequestInterface
*
* @return array
*/
public function getCookieParams()
public function getCookieParams(): array
{
// TODO: Implement getCookieParams() method.
return $this->cookies;
}
/**
@@ -53,9 +67,11 @@ class ServerRequest extends Request implements ServerRequestInterface
* @param array $cookies Array of key/value pairs representing cookies.
* @return static
*/
public function withCookieParams(array $cookies)
public function withCookieParams(array $cookies): static
{
// TODO: Implement withCookieParams() method.
$this->cookies = $cookies;
return $this;
}
/**
@@ -70,9 +86,10 @@ class ServerRequest extends Request implements ServerRequestInterface
*
* @return array
*/
public function getQueryParams()
public function getQueryParams(): array
{
// TODO: Implement getQueryParams() method.
return $this->query;
}
/**
@@ -97,9 +114,11 @@ class ServerRequest extends Request implements ServerRequestInterface
* $_GET.
* @return static
*/
public function withQueryParams(array $query)
public function withQueryParams(array $query): static
{
// TODO: Implement withQueryParams() method.
$this->query = $query;
return $this;
}
/**
@@ -114,9 +133,10 @@ class ServerRequest extends Request implements ServerRequestInterface
* @return array An array tree of UploadedFileInterface instances; an empty
* array MUST be returned if no data is present.
*/
public function getUploadedFiles()
public function getUploadedFiles(): array
{
// TODO: Implement getUploadedFiles() method.
return $this->files;
}
/**
@@ -130,9 +150,11 @@ class ServerRequest extends Request implements ServerRequestInterface
* @return static
* @throws \InvalidArgumentException if an invalid structure is provided.
*/
public function withUploadedFiles(array $uploadedFiles)
public function withUploadedFiles(array $uploadedFiles): static
{
// TODO: Implement withUploadedFiles() method.
$this->files = $uploadedFiles;
return $this;
}
/**
@@ -150,9 +172,10 @@ class ServerRequest extends Request implements ServerRequestInterface
* @return null|array|object The deserialized body parameters, if any.
* These will typically be an array or object.
*/
public function getParsedBody()
public function getParsedBody(): object|array|null
{
// TODO: Implement getParsedBody() method.
return $this->posts;
}
/**
@@ -183,9 +206,11 @@ class ServerRequest extends Request implements ServerRequestInterface
* @throws \InvalidArgumentException if an unsupported argument type is
* provided.
*/
public function withParsedBody($data)
public function withParsedBody($data): static
{
// TODO: Implement withParsedBody() method.
$this->posts = $data;
return $this;
}
/**
@@ -199,27 +224,31 @@ class ServerRequest extends Request implements ServerRequestInterface
*
* @return array Attributes derived from the request.
*/
public function getAttributes()
public function getAttributes(): array
{
// TODO: Implement getAttributes() method.
}/**
* Retrieve a single derived request attribute.
*
* Retrieves a single derived request attribute as described in
* getAttributes(). If the attribute has not been previously set, returns
* the default value as provided.
*
* This method obviates the need for a hasAttribute() method, as it allows
* specifying a default value to return if the attribute is not found.
*
* @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist.
* @return mixed
* @see getAttributes()
*/
public function getAttribute(string $name, $default = null)
return [];
}
/**
* Retrieve a single derived request attribute.
*
* Retrieves a single derived request attribute as described in
* getAttributes(). If the attribute has not been previously set, returns
* the default value as provided.
*
* This method obviates the need for a hasAttribute() method, as it allows
* specifying a default value to return if the attribute is not found.
*
* @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist.
* @return mixed
* @see getAttributes()
*/
public function getAttribute(string $name, $default = null): mixed
{
// TODO: Implement getAttribute() method.
return $default;
}
/**
@@ -237,9 +266,10 @@ class ServerRequest extends Request implements ServerRequestInterface
* @return static
* @see getAttributes()
*/
public function withAttribute(string $name, $value)
public function withAttribute(string $name, $value): static
{
// TODO: Implement withAttribute() method.
return $this;
}
/**
@@ -256,8 +286,9 @@ class ServerRequest extends Request implements ServerRequestInterface
* @return static
* @see getAttributes()
*/
public function withoutAttribute(string $name)
public function withoutAttribute(string $name): static
{
// TODO: Implement withoutAttribute() method.
return $this;
}
}
+86 -25
View File
@@ -1,12 +1,27 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use Psr\Http\Message\StreamInterface;
class Stream implements StreamInterface
{
public string $content = '';
public int $size = 0;
/**
* @param string $content
*/
public function __construct(string $content = '')
{
$this->content = $content;
}
/**
* Reads all data from the stream into a string, from the beginning to end.
*
@@ -24,6 +39,7 @@ class Stream implements StreamInterface
public function __toString()
{
// TODO: Implement __toString() method.
return $this->content;
}
/**
@@ -31,9 +47,14 @@ class Stream implements StreamInterface
*
* @return void
*/
public function close()
public function close(): void
{
// TODO: Implement close() method.
if (is_resource($this->content)) {
fclose($this->content);
} else {
$this->content = '';
}
}
/**
@@ -43,9 +64,10 @@ class Stream implements StreamInterface
*
* @return resource|null Underlying PHP stream, if any
*/
public function detach()
public function detach(): mixed
{
// TODO: Implement detach() method.
return null;
}
/**
@@ -53,9 +75,10 @@ class Stream implements StreamInterface
*
* @return int|null Returns the size in bytes if known, or null if unknown.
*/
public function getSize()
public function getSize(): ?int
{
// TODO: Implement getSize() method.
return $this->size;
}
/**
@@ -64,9 +87,10 @@ class Stream implements StreamInterface
* @return int Position of the file pointer
* @throws \RuntimeException on error.
*/
public function tell()
public function tell(): int
{
// TODO: Implement tell() method.
return 0;
}
/**
@@ -74,9 +98,10 @@ class Stream implements StreamInterface
*
* @return bool
*/
public function eof()
public function eof(): bool
{
// TODO: Implement eof() method.
return false;
}
/**
@@ -84,9 +109,10 @@ class Stream implements StreamInterface
*
* @return bool
*/
public function isSeekable()
public function isSeekable(): bool
{
// TODO: Implement isSeekable() method.
return true;
}
/**
@@ -101,22 +127,28 @@ class Stream implements StreamInterface
* SEEK_END: Set position to end-of-stream plus offset.
* @throws \RuntimeException on failure.
*/
public function seek(int $offset, int $whence = SEEK_SET)
public function seek(int $offset, int $whence = SEEK_SET): void
{
// TODO: Implement seek() method.
}/**
* Seek to the beginning of the stream.
*
* If the stream is not seekable, this method will raise an exception;
* otherwise, it will perform a seek(0).
*
* @throws \RuntimeException on failure.
* @link http://www.php.net/manual/en/function.fseek.php
* @see seek()
*/
public function rewind()
if (is_resource($this->content)) {
fseek($this->content, $offset, $whence);
}
}
/**
* Seek to the beginning of the stream.
*
* If the stream is not seekable, this method will raise an exception;
* otherwise, it will perform a seek(0).
*
* @throws \RuntimeException on failure.
* @link http://www.php.net/manual/en/function.fseek.php
* @see seek()
*/
public function rewind(): void
{
// TODO: Implement rewind() method.
$this->seek(0);
}
/**
@@ -124,9 +156,13 @@ class Stream implements StreamInterface
*
* @return bool
*/
public function isWritable()
public function isWritable(): bool
{
// TODO: Implement isWritable() method.
if (is_resource($this->content)) {
return is_writable($this->content);
}
return true;
}
/**
@@ -136,9 +172,17 @@ class Stream implements StreamInterface
* @return int Returns the number of bytes written to the stream.
* @throws \RuntimeException on failure.
*/
public function write(string $string)
public function write(string $string): int
{
// TODO: Implement write() method.
if (is_resource($this->content)) {
$this->content = fopen($string, 'wr');
$this->size = filesize($string);
} else {
$this->content = $string;
$this->size = mb_strlen($string);
}
return $this->size;
}
/**
@@ -146,9 +190,13 @@ class Stream implements StreamInterface
*
* @return bool
*/
public function isReadable()
public function isReadable(): bool
{
// TODO: Implement isReadable() method.
if (is_resource($this->content)) {
return is_readable($this->content);
}
return true;
}
/**
@@ -161,9 +209,14 @@ class Stream implements StreamInterface
* if no bytes are available.
* @throws \RuntimeException if an error occurs.
*/
public function read(int $length)
public function read(int $length): string
{
// TODO: Implement read() method.
if (!is_resource($this->content)) {
return mb_substr($this->content, 0, $length);
} else {
return fread($this->content, $length);
}
}
/**
@@ -173,9 +226,13 @@ class Stream implements StreamInterface
* @throws \RuntimeException if unable to read or an error occurs while
* reading.
*/
public function getContents()
public function getContents(): string
{
// TODO: Implement getContents() method.
if (is_resource($this->content)) {
return fread($this->content, $this->getSize());
}
return $this->content;
}
/**
@@ -190,8 +247,12 @@ class Stream implements StreamInterface
* provided. Returns a specific key value if a key is provided and the
* value is found, or null if the key is not found.
*/
public function getMetadata(?string $key = null)
public function getMetadata(?string $key = null): mixed
{
// TODO: Implement getMetadata() method.
if (is_resource($this->content)) {
return stream_get_meta_data($this->content);
}
return null;
}
}
+69 -16
View File
@@ -1,12 +1,21 @@
<?php
namespace Kiri\Router\Message;
namespace Kiri\Router\Constrict;
use Psr\Http\Message\UriInterface;
class Uri implements UriInterface
{
private string $scheme = '';
private string $host = '';
private int $port = 80;
private string $path = '';
private string $user = '';
private string $password = '';
private string $queryString;
private string $fragment;
/**
* Retrieve the scheme component of the URI.
*
@@ -21,9 +30,10 @@ class Uri implements UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.1
* @return string The URI scheme.
*/
public function getScheme()
public function getScheme(): string
{
// TODO: Implement getScheme() method.
return $this->scheme;
}
/**
@@ -44,9 +54,10 @@ class Uri implements UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.2
* @return string The URI authority, in "[user-info@]host[:port]" format.
*/
public function getAuthority()
public function getAuthority(): string
{
// TODO: Implement getAuthority() method.
return '';
}
/**
@@ -64,9 +75,10 @@ class Uri implements UriInterface
*
* @return string The URI user information, in "username[:password]" format.
*/
public function getUserInfo()
public function getUserInfo(): string
{
// TODO: Implement getUserInfo() method.
return $this->user . '[' . $this->password . ']';
}
/**
@@ -80,9 +92,10 @@ class Uri implements UriInterface
* @see http://tools.ietf.org/html/rfc3986#section-3.2.2
* @return string The URI host.
*/
public function getHost()
public function getHost(): string
{
// TODO: Implement getHost() method.
return $this->host;
}
/**
@@ -100,9 +113,10 @@ class Uri implements UriInterface
*
* @return null|int The URI port.
*/
public function getPort()
public function getPort(): ?int
{
// TODO: Implement getPort() method.
return $this->port;
}
/**
@@ -130,9 +144,10 @@ class Uri implements UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.3
* @return string The URI path.
*/
public function getPath()
public function getPath(): string
{
// TODO: Implement getPath() method.
return $this->path;
}
/**
@@ -155,9 +170,10 @@ class Uri implements UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.4
* @return string The URI query string.
*/
public function getQuery()
public function getQuery(): string
{
// TODO: Implement getQuery() method.
return $this->queryString;
}
/**
@@ -176,9 +192,10 @@ class Uri implements UriInterface
* @see https://tools.ietf.org/html/rfc3986#section-3.5
* @return string The URI fragment.
*/
public function getFragment()
public function getFragment(): string
{
// TODO: Implement getFragment() method.
return $this->fragment;
}
/**
@@ -196,9 +213,11 @@ class Uri implements UriInterface
* @return static A new instance with the specified scheme.
* @throws \InvalidArgumentException for invalid or unsupported schemes.
*/
public function withScheme(string $scheme)
public function withScheme(string $scheme): static
{
// TODO: Implement withScheme() method.
$this->scheme = $scheme;
return $this;
}
/**
@@ -215,9 +234,12 @@ class Uri implements UriInterface
* @param null|string $password The password associated with $user.
* @return static A new instance with the specified user information.
*/
public function withUserInfo(string $user, ?string $password = null)
public function withUserInfo(string $user, ?string $password = null): static
{
// TODO: Implement withUserInfo() method.
$this->user = $user;
$this->password = $password;
return $this;
}
/**
@@ -232,9 +254,11 @@ class Uri implements UriInterface
* @return static A new instance with the specified host.
* @throws \InvalidArgumentException for invalid hostnames.
*/
public function withHost(string $host)
public function withHost(string $host): static
{
// TODO: Implement withHost() method.
$this->host = $host;
return $this;
}
/**
@@ -254,9 +278,11 @@ class Uri implements UriInterface
* @return static A new instance with the specified port.
* @throws \InvalidArgumentException for invalid ports.
*/
public function withPort(?int $port)
public function withPort(?int $port): static
{
// TODO: Implement withPort() method.
$this->port = $port;
return $this;
}
/**
@@ -281,9 +307,11 @@ class Uri implements UriInterface
* @return static A new instance with the specified path.
* @throws \InvalidArgumentException for invalid paths.
*/
public function withPath(string $path)
public function withPath(string $path): static
{
// TODO: Implement withPath() method.
$this->path = $path;
return $this;
}
/**
@@ -301,9 +329,11 @@ class Uri implements UriInterface
* @return static A new instance with the specified query string.
* @throws \InvalidArgumentException for invalid query strings.
*/
public function withQuery(string $query)
public function withQuery(string $query): static
{
// TODO: Implement withQuery() method.
$this->queryString = $query;
return $this;
}
/**
@@ -320,9 +350,11 @@ class Uri implements UriInterface
* @param string $fragment The fragment to use with the new instance.
* @return static A new instance with the specified fragment.
*/
public function withFragment(string $fragment)
public function withFragment(string $fragment): static
{
// TODO: Implement withFragment() method.
$this->fragment = $fragment;
return $this;
}
/**
@@ -351,5 +383,26 @@ class Uri implements UriInterface
public function __toString()
{
// TODO: Implement __toString() method.
return $this->scheme . '://x.x.x.x:' . $this->port . '/' . $this->path . '?' . $this->queryString;
}
/**
* @param \Swoole\Http\Request $request
* @return UriInterface
*/
public static function parse(\Swoole\Http\Request $request): UriInterface
{
$uri = new static();
$uri->queryString = $request->server['query_string'];
$uri->path = $request->server['path_info'];
$uri->port = $request->server['server_port'];
if (isset($request->server['https']) && $request->server['https'] !== 'off') {
$uri->scheme = 'https';
} else {
$uri->scheme = 'http';
}
return $uri;
}
}