- Still WIP on Api's wrapper
This commit is contained in:
1 parent
7e69a09e7f
commit
5d9c0f0dbf
16 files changed
+548
-42
No files matched your search
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Api\Stream;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Ulmus\Api\Common\HttpHeaderEnum;
|
||||
use Ulmus\Api\Stream\Stream;
|
||||
use Ulmus\Api\Common\StreamOutputInterface;
|
||||
|
||||
class JsonStream extends Stream implements StreamOutputInterface
|
||||
{
|
||||
public const DEFAULT_JSON_ENCODING_FLAGS = JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_UNESCAPED_SLASHES;
|
||||
|
||||
public const DEFAULT_JSON_DECODING_FLAGS = JSON_THROW_ON_ERROR;
|
||||
|
||||
public int $depth = 1024;
|
||||
|
||||
public int $encodingOptions;
|
||||
|
||||
public int $decodingOptions;
|
||||
|
||||
public function __construct($encodingOptions = self::DEFAULT_JSON_ENCODING_FLAGS, $decodingOptions = self::DEFAULT_JSON_DECODING_FLAGS)
|
||||
{
|
||||
$this->encodingOptions = $encodingOptions;
|
||||
$this->decodingOptions = $decodingOptions;
|
||||
}
|
||||
|
||||
public static function fromContent(mixed $content, int $encodingOptions = self::DEFAULT_JSON_ENCODING_FLAGS) : StreamInterface
|
||||
{
|
||||
if ( false === $json = json_encode($content, $encodingOptions) ) {
|
||||
throw new \InvalidArgumentException(sprintf('Json encoding failed with message `%s`.', json_last_error_msg()));
|
||||
}
|
||||
|
||||
return static::fromJsonEncoded($json);
|
||||
}
|
||||
|
||||
public static function fromJsonEncoded(string $json) : StreamInterface
|
||||
{
|
||||
$obj = Stream::fromTemp($json);
|
||||
$obj->rewind();
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function render(): mixed
|
||||
{
|
||||
return json_decode($this->getContents(), true, $this->depth, $this->decodingOptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Api\Stream;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
class Stream implements StreamInterface
|
||||
{
|
||||
protected mixed $stream;
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContents();
|
||||
}
|
||||
|
||||
public static function fromTemp(string $content = "", string $mode = 'wb+') : StreamInterface
|
||||
{
|
||||
return static::fromMemory($content, $mode, "php://temp");
|
||||
}
|
||||
|
||||
public static function fromMemory(string $content = "", string $mode = 'wb+', string $destination = "php://memory") : StreamInterface
|
||||
{
|
||||
$obj = new static();
|
||||
$obj->create($destination, $mode);
|
||||
$obj->write($content);
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public function create(mixed $stream, string $mode) : void
|
||||
{
|
||||
if (is_string($stream)) {
|
||||
try {
|
||||
$stream = fopen($stream, $mode);
|
||||
} catch (\Throwable $e) {
|
||||
throw new \RuntimeException(sprintf('Invalid stream reference provided: %s', $error->getMessage()), 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_resource($stream) || $stream instanceof StreamInterface ) {
|
||||
$this->attach($stream);
|
||||
}
|
||||
else {
|
||||
throw new \RuntimeException("Given stream must be a resource, a StreamInterface or a string pointing to a stream destination for fopen.");
|
||||
}
|
||||
}
|
||||
|
||||
public function attach(mixed $stream) : void
|
||||
{
|
||||
$this->stream = $stream;
|
||||
}
|
||||
|
||||
public function detach() : mixed
|
||||
{
|
||||
$stream = $this->stream;
|
||||
unset($this->stream);
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
public function getSize(): null|int
|
||||
{
|
||||
if (false !== $result = fstat($this->stream)){
|
||||
return $result['size'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function tell() : int
|
||||
{
|
||||
if ( false === $result = ftell($this->stream) ) {
|
||||
throw new \RuntimeException("An error occured while trying to fetch current position pointer in a stream.");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function eof() : bool
|
||||
{
|
||||
return ! $this->stream || feof($this->stream);
|
||||
}
|
||||
|
||||
public function isSeekable() : bool
|
||||
{
|
||||
return stream_get_meta_data($this->stream)['seekable'] ?? false;
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET) : void
|
||||
{
|
||||
if (! $this->isSeekable()) {
|
||||
throw new \InvalidArgumentException("An error occured while trying to seek an unseekable stream.");
|
||||
}
|
||||
|
||||
if ( 0 !== fseek($this->stream, $offset, $whence) ) {
|
||||
throw new \RuntimeException("An error occured while trying to seek a position in a stream.");
|
||||
}
|
||||
}
|
||||
|
||||
public function rewind() : void
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function isWritable() : bool
|
||||
{
|
||||
return $this->hasMode('acwx+');
|
||||
}
|
||||
|
||||
public function write($string) : false|int
|
||||
{
|
||||
if (! $this->isWritable()) {
|
||||
throw new \UnexpectedValueException("An error occured while trying to seek an unseekable stream.");
|
||||
}
|
||||
|
||||
$result = fwrite($this->stream, $string);
|
||||
|
||||
if ( $result === false ) {
|
||||
throw new \UnexpectedValueException("fwrite() failed to write into stream.");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function close(): void
|
||||
{
|
||||
if (! $this->stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stream = $this->detach();
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
public function isReadable(): bool
|
||||
{
|
||||
return $this->hasMode('r+');
|
||||
}
|
||||
|
||||
public function read($length): string
|
||||
{
|
||||
if (! $this->isReadable()) {
|
||||
throw new \UnexpectedValueException("An error occured while trying to read a stream which was not readable.");
|
||||
}
|
||||
elseif ( false === $result = fread($this->stream, $length) )
|
||||
throw new \RuntimeException("Unreadable stream given; please check your stream's mode");{
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getContents(): string
|
||||
{
|
||||
if (! $this->isReadable()) {
|
||||
throw new \UnexpectedValueException("Unreadable stream given; please check your stream's mode");
|
||||
}
|
||||
|
||||
if ( $this->isSeekable() ) {
|
||||
$this->rewind();
|
||||
}
|
||||
|
||||
if (false === $result = stream_get_contents($this->stream)) {
|
||||
throw new \RuntimeException("Failure happened on stream_get_contents() from stream. ");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getMetadata(string $key = null) : mixed
|
||||
{
|
||||
$metadata = stream_get_meta_data($this->stream);
|
||||
|
||||
return is_null($key) ? $metadata : $metadata[$key] ?? null;
|
||||
}
|
||||
|
||||
protected function hasMode(string $search) : bool
|
||||
{
|
||||
$meta = stream_get_meta_data($this->stream);
|
||||
$mode = $meta['mode'];
|
||||
|
||||
return strpbrk($mode, $search) !== false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user