Updated libs to use custom exceptions.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/.idea/*
|
||||
/vendor/*
|
||||
/.env
|
||||
.phpunit.result.cache
|
||||
/.phpunit.result.cache
|
||||
/.vscode
|
||||
|
||||
65
bin/console
65
bin/console
@@ -6,46 +6,45 @@ declare(strict_types=1);
|
||||
use App\Command;
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('error_reporting', 'On');
|
||||
ini_set('display_errors', 'On');
|
||||
|
||||
require __DIR__ . '/../pre_init.php';
|
||||
|
||||
set_error_handler(function (int $number, mixed $error, mixed $file, int $line) {
|
||||
/**
|
||||
* Throws an exception based on an error code.
|
||||
*
|
||||
* @param int $number The error code.
|
||||
* @param mixed $error The error message.
|
||||
* @param mixed $file The file where the error occurred.
|
||||
* @param int $line The line number where the error occurred.
|
||||
*
|
||||
* @throws ErrorException When the error code is not suppressed by error_reporting.
|
||||
*/
|
||||
$errorHandler = function (int $number, mixed $error, mixed $file, int $line) {
|
||||
$errno = $number & error_reporting();
|
||||
static $errorLevels = [
|
||||
E_ERROR => 'Error',
|
||||
E_WARNING => 'Warning',
|
||||
E_PARSE => 'Parser Error',
|
||||
E_NOTICE => 'Notice',
|
||||
E_CORE_ERROR => 'Core Error',
|
||||
E_CORE_WARNING => 'Core Warning',
|
||||
E_COMPILE_ERROR => 'Compile Error',
|
||||
E_COMPILE_WARNING => 'Compile Warning',
|
||||
E_USER_ERROR => 'User Error',
|
||||
E_USER_WARNING => 'User Warning',
|
||||
E_USER_NOTICE => 'User notice',
|
||||
E_STRICT => 'Strict Notice',
|
||||
E_RECOVERABLE_ERROR => 'Recoverable Error'
|
||||
];
|
||||
|
||||
if (0 === $errno) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = sprintf('%s: %s (%s:%d).', $errorLevels[$number] ?? (string)$number, $error, $file, $line);
|
||||
fwrite(STDERR, trim($message) . PHP_EOL);
|
||||
|
||||
exit(501);
|
||||
});
|
||||
throw new ErrorException($error, $number, 1, $file, $line);
|
||||
};
|
||||
set_error_handler($errorHandler);
|
||||
|
||||
set_exception_handler(function (Throwable $e) {
|
||||
$message = sprintf('%s: %s (%s:%d).', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
|
||||
fwrite(STDERR, trim($message) . PHP_EOL);
|
||||
$message = strtr('{kind}: {message} ({file}:{line}).', [
|
||||
'{kind}' => $e::class,
|
||||
'{line}' => $e->getLine(),
|
||||
'{message}' => $e->getMessage(),
|
||||
'{file}' => after($e->getFile(), ROOT_PATH),
|
||||
]);
|
||||
|
||||
fwrite(STDERR, $message . PHP_EOL);
|
||||
exit(502);
|
||||
});
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
fwrite(STDERR, 'Dependencies are missing.' . PHP_EOL);
|
||||
print 'Dependencies are missing please refer to https://github.com/arabcoders/watchstate/blob/master/FAQ.md';
|
||||
exit(Command::FAILURE);
|
||||
}
|
||||
|
||||
@@ -54,14 +53,16 @@ require __DIR__ . '/../vendor/autoload.php';
|
||||
try {
|
||||
$app = (new App\Libs\Initializer())->boot();
|
||||
} catch (Throwable $e) {
|
||||
$message = sprintf(
|
||||
'Unhandled Exception [%s] was thrown in CLI boot context. With message [%s] in [%s:%d].',
|
||||
$e::class,
|
||||
$e->getMessage(),
|
||||
array_reverse(explode(ROOT_PATH, $e->getFile(), 2))[0],
|
||||
$e->getLine()
|
||||
$message = strtr(
|
||||
'CLI: Exception [{kind}] was thrown unhandled during CLI boot context. Error [{message} @ {file}:{line}].',
|
||||
[
|
||||
'{kind}' => $e::class,
|
||||
'{line}' => $e->getLine(),
|
||||
'{message}' => $e->getMessage(),
|
||||
'{file}' => array_reverse(explode(ROOT_PATH, $e->getFile(), 2))[0],
|
||||
]
|
||||
);
|
||||
fwrite(STDERR, trim($message) . PHP_EOL);
|
||||
fwrite(STDERR, $message . PHP_EOL);
|
||||
exit(503);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Libs\Database\DatabaseInterface as iDB;
|
||||
use App\Libs\Database\PDO\PDOAdapter;
|
||||
use App\Libs\Entity\StateEntity;
|
||||
use App\Libs\Entity\StateInterface;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Extends\ConsoleOutput;
|
||||
use App\Libs\Extends\HttpClient;
|
||||
use App\Libs\Extends\LogMessageProcessor;
|
||||
|
||||
@@ -17,23 +17,35 @@ if (!file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
set_error_handler(function (int $number, mixed $error, mixed $file, int $line) {
|
||||
/**
|
||||
* Throws an exception based on an error code.
|
||||
*
|
||||
* @param int $number The error code.
|
||||
* @param mixed $error The error message.
|
||||
* @param mixed $file The file where the error occurred.
|
||||
* @param int $line The line number where the error occurred.
|
||||
*
|
||||
* @throws ErrorException When the error code is not suppressed by error_reporting.
|
||||
*/
|
||||
$errorHandler = function (int $number, mixed $error, mixed $file, int $line) {
|
||||
$errno = $number & error_reporting();
|
||||
if (0 === $errno) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = trim(sprintf('%s: %s (%s:%d)', $number, $error, $file, $line));
|
||||
$out = fn($message) => inContainer() ? fwrite(STDERR, $message) : syslog(LOG_ERR, $message);
|
||||
$out($message);
|
||||
throw new ErrorException($error, $number, 1, $file, $line);
|
||||
};
|
||||
|
||||
exit(Command::FAILURE);
|
||||
});
|
||||
set_error_handler($errorHandler);
|
||||
|
||||
set_exception_handler(function (Throwable $e) {
|
||||
$message = trim(sprintf("%s: %s (%s:%d).", get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()));
|
||||
$out = fn($message) => inContainer() ? fwrite(STDERR, $message) : syslog(LOG_ERR, $message);
|
||||
$out($message);
|
||||
$out(r(text: '{kind}: {message} ({file}:{line}).', context: [
|
||||
'kind' => $e::class,
|
||||
'line' => $e->getLine(),
|
||||
'message' => $e->getMessage(),
|
||||
'file' => after($e->getFile(), ROOT_PATH),
|
||||
]));
|
||||
exit(Command::FAILURE);
|
||||
});
|
||||
|
||||
@@ -45,16 +57,17 @@ try {
|
||||
|
||||
$app = (new App\Libs\Initializer())->boot();
|
||||
} catch (Throwable $e) {
|
||||
fwrite(
|
||||
STDERR,
|
||||
trim(
|
||||
sprintf(
|
||||
'Unhandled Exception [%s] was thrown at HTTP boot context. With message [%s] in [%s:%d].',
|
||||
$e::class,
|
||||
$e->getMessage(),
|
||||
array_reverse(explode(ROOT_PATH, $e->getFile(), 2))[0],
|
||||
$e->getLine()
|
||||
)
|
||||
$out = fn($message) => inContainer() ? fwrite(STDERR, $message) : syslog(LOG_ERR, $message);
|
||||
|
||||
$out(
|
||||
r(
|
||||
text: 'HTTP: Exception [{kind}] was thrown unhandled during HTTP boot context. Error [{message} @ {file}:{line}].',
|
||||
context: [
|
||||
'kind' => $e::class,
|
||||
'line' => $e->getLine(),
|
||||
'message' => $e->getMessage(),
|
||||
'file' => after($e->getFile(), ROOT_PATH),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ use App\Backends\Jellyfin\JellyfinClient;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\HttpException;
|
||||
use App\Libs\Exceptions\HttpException;
|
||||
use App\Libs\Mappers\ImportInterface as iImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\QueueRequests;
|
||||
|
||||
@@ -27,7 +27,7 @@ use App\Backends\Jellyfin\Action\SearchQuery;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\HttpException;
|
||||
use App\Libs\Exceptions\HttpException;
|
||||
use App\Libs\Mappers\ImportInterface as iImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\QueueRequests;
|
||||
|
||||
@@ -29,7 +29,7 @@ use App\Backends\Plex\Action\SearchQuery;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\HttpException;
|
||||
use App\Libs\Exceptions\HttpException;
|
||||
use App\Libs\Mappers\ImportInterface as iImport;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\QueueRequests;
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace App;
|
||||
|
||||
use App\Backends\Common\ClientInterface as iClient;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use Closure;
|
||||
use DirectoryIterator;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Command\Command as BaseCommand;
|
||||
use Symfony\Component\Console\Command\LockableTrait;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
|
||||
@@ -14,8 +14,8 @@ use App\Libs\Message;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\QueueRequests;
|
||||
use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Monolog\Logger;
|
||||
use Nyholm\Psr7\Stream;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
||||
@@ -17,8 +17,8 @@ use App\Libs\Mappers\ImportInterface as iImport;
|
||||
use App\Libs\Message;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Routable;
|
||||
use App\Libs\Stream;
|
||||
use Monolog\Logger;
|
||||
use Nyholm\Psr7\Stream;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
|
||||
@@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Extends\PSRContainer as BaseContainer;
|
||||
use League\Container\ReflectionContainer;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Container class provides a dependency injection container implementation.
|
||||
|
||||
12
src/Libs/Exceptions/ErrorException.php
Normal file
12
src/Libs/Exceptions/ErrorException.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Libs\Exceptions;
|
||||
|
||||
/**
|
||||
* Class ErrorException
|
||||
*/
|
||||
class ErrorException extends \ErrorException
|
||||
{
|
||||
}
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use RuntimeException;
|
||||
namespace App\Libs\Exceptions;
|
||||
|
||||
class HttpException extends RuntimeException
|
||||
{
|
||||
12
src/Libs/Exceptions/InvalidArgumentException.php
Normal file
12
src/Libs/Exceptions/InvalidArgumentException.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Libs\Exceptions;
|
||||
|
||||
/**
|
||||
* Class InvalidArgumentException
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace App\Libs\Extends;
|
||||
use App\Libs\Config;
|
||||
use DateTimeInterface;
|
||||
use Monolog\LogRecord;
|
||||
use Nyholm\Psr7\Stream;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
@@ -17,7 +17,7 @@ class StreamLogHandler extends ConsoleHandler
|
||||
/**
|
||||
* Constructor method for the class.
|
||||
*
|
||||
* @param Stream $stream The Stream object used for logging.
|
||||
* @param StreamInterface $stream The Stream object used for logging.
|
||||
* @param OutputInterface|null $output (optional) The OutputInterface object to handle the output. Default is null.
|
||||
* @param bool $bubble (optional) Flag to determine if the log messages should bubble up the logging hierarchy. Default is true.
|
||||
* @param array $levelsMapper (optional) An array that maps log levels to specific handlers. Default is an empty array.
|
||||
@@ -25,7 +25,7 @@ class StreamLogHandler extends ConsoleHandler
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
private Stream $stream,
|
||||
private StreamInterface $stream,
|
||||
OutputInterface|null $output = null,
|
||||
bool $bubble = true,
|
||||
array $levelsMapper = []
|
||||
|
||||
@@ -4,10 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use JsonSerializable;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RuntimeException;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
@@ -17,7 +16,8 @@ use Stringable;
|
||||
* retrieve the supported external id sources, and obtain the pointers linking the
|
||||
* entity to the external ids.
|
||||
*
|
||||
* @implements JsonSerializable, Stringable
|
||||
* @implements JsonSerializable
|
||||
* @implements Stringable
|
||||
*/
|
||||
final class Guid implements JsonSerializable, Stringable
|
||||
{
|
||||
@@ -210,8 +210,7 @@ final class Guid implements JsonSerializable, Stringable
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws RuntimeException When source db not supported.
|
||||
* @throws InvalidArgumentException When id validation fails.
|
||||
* @throws InvalidArgumentException if the db source is not supported or the value validation fails.
|
||||
*/
|
||||
public static function validate(string $db, string|int $id): bool
|
||||
{
|
||||
@@ -220,7 +219,7 @@ final class Guid implements JsonSerializable, Stringable
|
||||
$lookup = 'guid_' . $db;
|
||||
|
||||
if (false === array_key_exists($lookup, self::SUPPORTED)) {
|
||||
throw new RuntimeException(
|
||||
throw new InvalidArgumentException(
|
||||
r('Invalid db [{db}] source was given. Expecting [{db_list}].', [
|
||||
'db' => $db,
|
||||
'db_list' => implode(', ', array_map(fn($f) => after($f, 'guid_'), array_keys(self::SUPPORTED))),
|
||||
@@ -232,7 +231,7 @@ final class Guid implements JsonSerializable, Stringable
|
||||
return true;
|
||||
}
|
||||
|
||||
if (1 !== preg_match(self::VALIDATE_GUID[$lookup]['pattern'], $id)) {
|
||||
if (1 !== @preg_match(self::VALIDATE_GUID[$lookup]['pattern'], $id)) {
|
||||
throw new InvalidArgumentException(
|
||||
r('Invalid [{value}] value for [{db}]. Expecting [{example}].', [
|
||||
'db' => $db,
|
||||
|
||||
@@ -6,6 +6,9 @@ namespace App\Libs;
|
||||
|
||||
use App\Cli;
|
||||
use App\Libs\Entity\StateInterface as iState;
|
||||
use App\Libs\Exceptions\Backends\RuntimeException;
|
||||
use App\Libs\Exceptions\HttpException;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Extends\ConsoleHandler;
|
||||
use App\Libs\Extends\ConsoleOutput;
|
||||
use Closure;
|
||||
@@ -24,8 +27,6 @@ use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as iRequest;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
@@ -129,7 +130,6 @@ final class Initializer
|
||||
if (!(error_reporting() & $severity)) {
|
||||
return;
|
||||
}
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
throw new ErrorException($message, 0, $severity, $file, $line);
|
||||
}
|
||||
);
|
||||
@@ -222,7 +222,8 @@ final class Initializer
|
||||
* @param iRequest $realRequest The incoming HTTP request.
|
||||
*
|
||||
* @return ResponseInterface The HTTP response.
|
||||
* @throws InvalidArgumentException If an error occurs.
|
||||
*
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException If an error occurs.
|
||||
*/
|
||||
private function defaultHttpServer(iRequest $realRequest): ResponseInterface
|
||||
{
|
||||
@@ -262,7 +263,7 @@ final class Initializer
|
||||
|
||||
try {
|
||||
$class = makeBackend($info, $name);
|
||||
} catch (RuntimeException $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$this->write(
|
||||
request: $request,
|
||||
level: Level::Error,
|
||||
|
||||
@@ -15,8 +15,7 @@ use DateTimeInterface as iDate;
|
||||
use Exception;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
|
||||
/**
|
||||
* DirectMapper Class.
|
||||
@@ -73,9 +72,9 @@ final class DirectMapper implements iImport
|
||||
*
|
||||
* @param iLogger $logger The logger instance.
|
||||
* @param iDB $db The database instance.
|
||||
* @param CacheInterface $cache The cache instance.
|
||||
* @param iCache $cache The cache instance.
|
||||
*/
|
||||
public function __construct(protected iLogger $logger, protected iDB $db, protected CacheInterface $cache)
|
||||
public function __construct(protected iLogger $logger, protected iDB $db, protected iCache $cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -632,7 +631,7 @@ final class DirectMapper implements iImport
|
||||
$progress[$itemId] = $entity;
|
||||
}
|
||||
$this->cache->set('progress', $progress, new DateInterval('P1D'));
|
||||
} catch (InvalidArgumentException) {
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ use DateInterval;
|
||||
use DateTimeInterface as iDate;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface as iLogger;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use Psr\SimpleCache\CacheInterface as iCache;
|
||||
|
||||
/**
|
||||
* MemoryMapper Class
|
||||
@@ -63,9 +62,9 @@ final class MemoryMapper implements iImport
|
||||
*
|
||||
* @param iLogger $logger The instance of the logger interface.
|
||||
* @param iDB $db The instance of the database interface.
|
||||
* @param CacheInterface $cache The instance of the cache interface.
|
||||
* @param iCache $cache The instance of the cache interface.
|
||||
*/
|
||||
public function __construct(protected iLogger $logger, protected iDB $db, protected CacheInterface $cache)
|
||||
public function __construct(protected iLogger $logger, protected iDB $db, protected iCache $cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -455,7 +454,7 @@ final class MemoryMapper implements iImport
|
||||
$progress[$itemId] = $entity;
|
||||
}
|
||||
$this->cache->set('progress', $progress, new DateInterval('P1D'));
|
||||
} catch (InvalidArgumentException) {
|
||||
} catch (\Psr\SimpleCache\InvalidArgumentException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,16 +13,14 @@ use Attribute;
|
||||
* The attribute can be repeated, and it can target a class.
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
|
||||
final class Routable
|
||||
final readonly class Routable
|
||||
{
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $command The command string.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(public readonly string $command)
|
||||
public function __construct(public string $command)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,27 +4,30 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use FilesystemIterator;
|
||||
use PhpToken;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use RuntimeException;
|
||||
use SplFileInfo;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Router class handles the generation of routes based on scanned directories and class attributes.
|
||||
* Class Router
|
||||
*
|
||||
* The Router class is responsible for generating an array of routes by scanning directories.
|
||||
* It parses PHP files to extract namespaces and classes, and retrieves routes using reflection.
|
||||
*/
|
||||
final class Router
|
||||
final readonly class Router
|
||||
{
|
||||
/**
|
||||
* Class constructor.
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param array $dirs An optional array of directories.
|
||||
* @param array $dirs An array containing directory names.
|
||||
*/
|
||||
public function __construct(private readonly array $dirs = [])
|
||||
public function __construct(private array $dirs)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -132,14 +135,7 @@ final class Router
|
||||
$classes = [];
|
||||
$namespace = '';
|
||||
|
||||
if (false === ($content = @file_get_contents($file))) {
|
||||
throw new RuntimeException(r("Unable to read '{file}' - '{message}'.", [
|
||||
'file' => $file,
|
||||
'message' => error_get_last()['message'] ?? 'unknown',
|
||||
]));
|
||||
}
|
||||
|
||||
$tokens = PhpToken::tokenize($content);
|
||||
$tokens = PhpToken::tokenize((string)(new Stream($file, 'r')));
|
||||
$count = count($tokens);
|
||||
|
||||
foreach ($tokens as $i => $iValue) {
|
||||
|
||||
@@ -4,8 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use Closure;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Process\PhpExecutableFinder;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
|
||||
375
src/Libs/Stream.php
Normal file
375
src/Libs/Stream.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use GdImage;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Stringable;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Class Stream
|
||||
*
|
||||
* The Stream class represents a stream resource or file path.
|
||||
*
|
||||
* @implements StreamInterface
|
||||
*/
|
||||
final class Stream implements StreamInterface, Stringable
|
||||
{
|
||||
/**
|
||||
* @var array<string> A list of allowed stream resource types that are allowed to instantiate a stream
|
||||
*/
|
||||
private const ALLOWED_STREAM_RESOURCE_TYPES = ['gd', 'stream'];
|
||||
|
||||
/**
|
||||
* @var resource|null The underlying stream resource.
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
/**
|
||||
* @param string|resource $stream The stream resource or file path.
|
||||
* @param string $mode The stream mode. Default is 'r'.
|
||||
*
|
||||
* @throws RuntimeException If an invalid stream reference is provided.
|
||||
* @throws InvalidArgumentException If the stream type is unexpected.
|
||||
*/
|
||||
public function __construct(mixed $stream, string $mode = 'r')
|
||||
{
|
||||
$error = null;
|
||||
$resource = $stream;
|
||||
|
||||
if (is_string($stream)) {
|
||||
set_error_handler(function ($e) use (&$error) {
|
||||
if ($e !== E_WARNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $e;
|
||||
});
|
||||
$resource = fopen($stream, $mode);
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
throw new RuntimeException(r('Stream: Invalid stream reference provided. Error {error}.', [
|
||||
'error' => ag(error_get_last(), 'message', '??'),
|
||||
]));
|
||||
}
|
||||
|
||||
if (!self::isValidStreamResourceType($resource)) {
|
||||
throw new InvalidArgumentException(
|
||||
r(
|
||||
text: 'Stream: Unexpected [{type}] type was given. Stream must be a file path or stream resource.',
|
||||
context: [
|
||||
'type' => gettype($resource),
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Stream instance.
|
||||
*
|
||||
* @param string|resource $stream The stream resource or file path.
|
||||
* @param string $mode The stream mode. Default is 'r'.
|
||||
*
|
||||
* @return StreamInterface The new Stream instance.
|
||||
*
|
||||
* @throws RuntimeException If an invalid stream reference is provided.
|
||||
* @throws InvalidArgumentException If the stream type is unexpected.
|
||||
*/
|
||||
public static function make(mixed $stream, string $mode = 'r'): StreamInterface
|
||||
{
|
||||
return new self($stream, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create in-memory stream with given contents.
|
||||
*
|
||||
* @param string|resource|StreamInterface $body The stream contents.
|
||||
*
|
||||
* @throws InvalidArgumentException If the $body arg is not a string, resource or StreamInterface.
|
||||
*/
|
||||
public static function create(mixed $body = ''): StreamInterface
|
||||
{
|
||||
if ($body instanceof StreamInterface) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
if (is_string($body)) {
|
||||
$resource = \fopen('php://memory', 'r+');
|
||||
fwrite($resource, $body);
|
||||
fseek($resource, 0);
|
||||
return new self($resource);
|
||||
}
|
||||
|
||||
if (!self::isValidStreamResourceType($body)) {
|
||||
throw new InvalidArgumentException(
|
||||
'First argument to Stream::create() must be a string, resource or StreamInterface'
|
||||
);
|
||||
}
|
||||
|
||||
return new self($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
if (!$this->isReadable()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($this->isSeekable()) {
|
||||
$this->rewind();
|
||||
}
|
||||
|
||||
return $this->getContents();
|
||||
} catch (Throwable) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close(): void
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
$resource = $this->detach();
|
||||
fclose($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$resource = $this->resource;
|
||||
$this->resource = null;
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize(): ?int
|
||||
{
|
||||
if (null === $this->resource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$stats = fstat($this->resource);
|
||||
if (false !== $stats) {
|
||||
return $stats['size'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function tell(): int
|
||||
{
|
||||
if (!$this->resource) {
|
||||
throw new RuntimeException('Stream: No resource available; cannot tell position');
|
||||
}
|
||||
|
||||
$result = ftell($this->resource);
|
||||
|
||||
if (!is_int($result)) {
|
||||
throw new RuntimeException('Stream: Error occurred during tell operation.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function eof(): bool
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return feof($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isSeekable(): bool
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
return $meta['seekable'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET): void
|
||||
{
|
||||
if (!$this->resource) {
|
||||
throw new RuntimeException('Stream: No resource available; cannot seek position');
|
||||
}
|
||||
|
||||
if (!$this->isSeekable()) {
|
||||
throw new RuntimeException('Stream: Stream is not seekable');
|
||||
}
|
||||
|
||||
$result = fseek($this->resource, $offset, $whence);
|
||||
|
||||
if (0 !== $result) {
|
||||
throw new RuntimeException('Stream: Error seeking within stream');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind(): void
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isWritable(): bool
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
$mode = $meta['mode'];
|
||||
|
||||
return (str_contains($mode, 'x') || str_contains($mode, 'w') ||
|
||||
str_contains($mode, 'c') || str_contains($mode, 'a') || str_contains($mode, '+'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function write(string $string): int
|
||||
{
|
||||
if (!$this->resource) {
|
||||
throw new RuntimeException('Stream: No resource available; cannot write.');
|
||||
}
|
||||
|
||||
if (!$this->isWritable()) {
|
||||
throw new RuntimeException('Stream: Stream is not writable.');
|
||||
}
|
||||
|
||||
$result = fwrite($this->resource, $string);
|
||||
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Stream: Error writing to stream.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isReadable(): bool
|
||||
{
|
||||
if (!$this->resource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->resource);
|
||||
$mode = $meta['mode'];
|
||||
|
||||
return str_contains($mode, 'r') || str_contains($mode, '+');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read(int $length): string
|
||||
{
|
||||
if (!$this->resource) {
|
||||
throw new RuntimeException('Stream: No resource available; cannot read');
|
||||
}
|
||||
|
||||
if (!$this->isReadable()) {
|
||||
throw new RuntimeException('Stream: Stream is not readable');
|
||||
}
|
||||
|
||||
$result = fread($this->resource, $length);
|
||||
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Stream: Error reading stream');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContents(): string
|
||||
{
|
||||
if (!$this->isReadable()) {
|
||||
throw new RuntimeException('Stream: Stream is not readable.');
|
||||
}
|
||||
|
||||
$result = stream_get_contents($this->resource);
|
||||
|
||||
if (false === $result) {
|
||||
throw new RuntimeException('Stream: Error reading stream');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadata(string|null $key = null)
|
||||
{
|
||||
$metadata = stream_get_meta_data($this->resource);
|
||||
|
||||
return null !== $key ? ($metadata[$key] ?? null) : $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a resource is one of the resource types allowed to instantiate a Stream
|
||||
*
|
||||
* @param resource $resource Stream resource.
|
||||
*
|
||||
* @return bool True if the resource is one of the allowed types, false otherwise.
|
||||
*/
|
||||
private static function isValidStreamResourceType($resource): bool
|
||||
{
|
||||
if (is_resource($resource)) {
|
||||
return in_array(get_resource_type($resource), self::ALLOWED_STREAM_RESOURCE_TYPES, true);
|
||||
}
|
||||
|
||||
if (PHP_VERSION_ID >= 80000 && $resource instanceof GdImage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Libs;
|
||||
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
@@ -154,7 +155,7 @@ final class Uri implements UriInterface, Stringable
|
||||
public function withScheme($scheme): self
|
||||
{
|
||||
if (!\is_string($scheme)) {
|
||||
throw new \InvalidArgumentException('Scheme must be a string');
|
||||
throw new InvalidArgumentException('Scheme must be a string');
|
||||
}
|
||||
|
||||
if ($this->scheme === $scheme = \strtr($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) {
|
||||
@@ -188,7 +189,7 @@ final class Uri implements UriInterface, Stringable
|
||||
public function withHost($host): self
|
||||
{
|
||||
if (!\is_string($host)) {
|
||||
throw new \InvalidArgumentException('Host must be a string');
|
||||
throw new InvalidArgumentException('Host must be a string');
|
||||
}
|
||||
|
||||
if ($this->host === $host = \strtr($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')) {
|
||||
@@ -312,7 +313,7 @@ final class Uri implements UriInterface, Stringable
|
||||
|
||||
$port = (int)$port;
|
||||
if (0 > $port || 0xFFFF < $port) {
|
||||
throw new \InvalidArgumentException(\sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
|
||||
throw new InvalidArgumentException(\sprintf('Invalid port: %d. Must be between 0 and 65535', $port));
|
||||
}
|
||||
|
||||
return self::isNonStandardPort($this->scheme, $port) ? $port : null;
|
||||
@@ -321,7 +322,7 @@ final class Uri implements UriInterface, Stringable
|
||||
private function filterPath($path): string
|
||||
{
|
||||
if (!is_string($path)) {
|
||||
throw new \InvalidArgumentException('Path must be a string');
|
||||
throw new InvalidArgumentException('Path must be a string');
|
||||
}
|
||||
|
||||
return preg_replace_callback(
|
||||
@@ -334,7 +335,7 @@ final class Uri implements UriInterface, Stringable
|
||||
private function filterQueryAndFragment($str): string
|
||||
{
|
||||
if (!is_string($str)) {
|
||||
throw new \InvalidArgumentException('Query and fragment must be a string');
|
||||
throw new InvalidArgumentException('Query and fragment must be a string');
|
||||
}
|
||||
|
||||
return preg_replace_callback(
|
||||
|
||||
@@ -8,15 +8,18 @@ use App\Backends\Common\Context;
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Container;
|
||||
use App\Libs\Entity\StateInterface as iFace;
|
||||
use App\Libs\Exceptions\InvalidArgumentException;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\Extends\Date;
|
||||
use App\Libs\Options;
|
||||
use App\Libs\Router;
|
||||
use App\Libs\Stream;
|
||||
use App\Libs\Uri;
|
||||
use Monolog\Utils;
|
||||
use Nyholm\Psr7\Response;
|
||||
use Nyholm\Psr7\Stream;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\SimpleCache\CacheInterface;
|
||||
@@ -300,9 +303,9 @@ if (!function_exists('saveWebhookPayload')) {
|
||||
*
|
||||
* @param iFace $entity Entity object.
|
||||
* @param ServerRequestInterface $request Request object.
|
||||
* @param Stream|null $file When given a stream, it will be used to write payload.
|
||||
* @param StreamInterface|null $file When given a stream, it will be used to write payload.
|
||||
*/
|
||||
function saveWebhookPayload(iFace $entity, ServerRequestInterface $request, Stream|null $file = null): void
|
||||
function saveWebhookPayload(iFace $entity, ServerRequestInterface $request, StreamInterface|null $file = null): void
|
||||
{
|
||||
$content = [
|
||||
'request' => [
|
||||
@@ -315,38 +318,27 @@ if (!function_exists('saveWebhookPayload')) {
|
||||
'entity' => $entity->getAll(),
|
||||
];
|
||||
|
||||
$closeStream = false;
|
||||
if (null === $file) {
|
||||
$fp = @fopen(
|
||||
r('{path}/webhooks/' . Config::get('webhook.file_format', 'webhook.{backend}.{event}.{id}.json'), [
|
||||
'path' => Config::get('tmpDir'),
|
||||
'time' => (string)time(),
|
||||
'backend' => $entity->via,
|
||||
'event' => ag($entity->getExtra($entity->via), 'event', 'unknown'),
|
||||
'id' => ag($request->getServerParams(), 'X_REQUEST_ID', time()),
|
||||
'date' => makeDate('now')->format('Ymd'),
|
||||
'context' => $content,
|
||||
]),
|
||||
'w'
|
||||
);
|
||||
$stream = $file ?? new Stream(
|
||||
r('{path}/webhooks/' . Config::get('webhook.file_format', 'webhook.{backend}.{event}.{id}.json'), [
|
||||
'path' => Config::get('tmpDir'),
|
||||
'time' => (string)time(),
|
||||
'backend' => $entity->via,
|
||||
'event' => ag($entity->getExtra($entity->via), 'event', 'unknown'),
|
||||
'id' => ag($request->getServerParams(), 'X_REQUEST_ID', time()),
|
||||
'date' => makeDate('now')->format('Ymd'),
|
||||
'context' => $content,
|
||||
]), 'w'
|
||||
);
|
||||
|
||||
if (false === $fp) {
|
||||
throw new Error(ag(error_get_last(), 'message', ''));
|
||||
}
|
||||
|
||||
$file = new Stream($fp);
|
||||
$closeStream = true;
|
||||
}
|
||||
|
||||
$file->write(
|
||||
$stream->write(
|
||||
json_encode(
|
||||
value: $content,
|
||||
flags: JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE | JSON_UNESCAPED_UNICODE
|
||||
)
|
||||
);
|
||||
|
||||
if ($closeStream) {
|
||||
$file->close();
|
||||
if (null === $file) {
|
||||
$stream->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,9 +348,9 @@ if (!function_exists('saveRequestPayload')) {
|
||||
* Save request payload to stream.
|
||||
*
|
||||
* @param ServerRequestInterface $request Request object.
|
||||
* @param Stream|null $file When given a stream, it will be used to write payload.
|
||||
* @param StreamInterface|null $file When given a stream, it will be used to write payload.
|
||||
*/
|
||||
function saveRequestPayload(ServerRequestInterface $request, Stream|null $file = null): void
|
||||
function saveRequestPayload(ServerRequestInterface $request, StreamInterface|null $file = null): void
|
||||
{
|
||||
$content = [
|
||||
'query' => $request->getQueryParams(),
|
||||
@@ -368,33 +360,20 @@ if (!function_exists('saveRequestPayload')) {
|
||||
'attributes' => $request->getAttributes(),
|
||||
];
|
||||
|
||||
$closeStream = false;
|
||||
if (null === $file) {
|
||||
$fp = @fopen(
|
||||
r('{path}/debug/request.{id}.json', [
|
||||
'path' => Config::get('tmpDir'),
|
||||
'id' => ag($request->getServerParams(), 'X_REQUEST_ID', (string)time()),
|
||||
]),
|
||||
'w'
|
||||
);
|
||||
$stream = $file ?? new Stream(r('{path}/debug/request.{id}.json', [
|
||||
'path' => Config::get('tmpDir'),
|
||||
'id' => ag($request->getServerParams(), 'X_REQUEST_ID', (string)time()),
|
||||
]), 'w');
|
||||
|
||||
if (false === $fp) {
|
||||
throw new Error(ag(error_get_last(), 'message', ''));
|
||||
}
|
||||
|
||||
$file = new Stream($fp);
|
||||
$closeStream = true;
|
||||
}
|
||||
|
||||
$file->write(
|
||||
$stream->write(
|
||||
json_encode(
|
||||
value: $content,
|
||||
flags: JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_IGNORE | JSON_UNESCAPED_UNICODE
|
||||
)
|
||||
);
|
||||
|
||||
if ($closeStream) {
|
||||
$file->close();
|
||||
if (null === $file) {
|
||||
$stream->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,20 +533,20 @@ if (!function_exists('makeBackend')) {
|
||||
* @param string|null $name server name.
|
||||
*
|
||||
* @return iClient backend client instance.
|
||||
* @throws RuntimeException if configuration is wrong.
|
||||
* @throws InvalidArgumentException if configuration is wrong.
|
||||
*/
|
||||
function makeBackend(array $backend, string|null $name = null): iClient
|
||||
{
|
||||
if (null === ($backendType = ag($backend, 'type'))) {
|
||||
throw new RuntimeException('No backend type was set.');
|
||||
throw new InvalidArgumentException('No backend type was set.');
|
||||
}
|
||||
|
||||
if (null === ag($backend, 'url')) {
|
||||
throw new RuntimeException('No backend url was set.');
|
||||
throw new InvalidArgumentException('No backend url was set.');
|
||||
}
|
||||
|
||||
if (null === ($class = Config::get("supported.{$backendType}", null))) {
|
||||
throw new RuntimeException(
|
||||
throw new InvalidArgumentException(
|
||||
r('Unexpected client type [{type}] was given. Expecting [{list}]', [
|
||||
'type' => $backendType,
|
||||
'list' => array_keys(Config::get('supported', [])),
|
||||
@@ -645,7 +624,7 @@ if (!function_exists('commandContext')) {
|
||||
]);
|
||||
}
|
||||
|
||||
return ($_SERVER['argv'][0] ?? 'php console') . ' ';
|
||||
return ($_SERVER['argv'][0] ?? 'php bin/console') . ' ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +780,7 @@ if (false === function_exists('isIgnoredId')) {
|
||||
* @param int|string|null $backendId The backend ID (optional).
|
||||
*
|
||||
* @return bool Returns true if the ID is ignored, false otherwise.
|
||||
* @throws RuntimeException Throws an exception if an invalid context type is given.
|
||||
* @throws InvalidArgumentException Throws an exception if an invalid context type is given.
|
||||
*/
|
||||
function isIgnoredId(
|
||||
string $backend,
|
||||
@@ -811,7 +790,7 @@ if (false === function_exists('isIgnoredId')) {
|
||||
string|int|null $backendId = null
|
||||
): bool {
|
||||
if (false === in_array($type, iFace::TYPES_LIST)) {
|
||||
throw new RuntimeException(sprintf('Invalid context type \'%s\' was given.', $type));
|
||||
throw new InvalidArgumentException(sprintf('Invalid context type \'%s\' was given.', $type));
|
||||
}
|
||||
|
||||
$list = Config::get('ignore', []);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Tests\Libs;
|
||||
|
||||
use App\Libs\Config;
|
||||
use App\Libs\Entity\StateEntity;
|
||||
use App\Libs\Exceptions\RuntimeException;
|
||||
use App\Libs\TestCase;
|
||||
use JsonMachine\Items;
|
||||
use JsonMachine\JsonDecoder\ErrorWrappingDecoder;
|
||||
@@ -273,7 +274,7 @@ class HelpersTest extends TestCase
|
||||
'saveWebhookPayload() should save webhook payload into given stream if it is provided otherwise it should save it into default stream.'
|
||||
);
|
||||
|
||||
$this->expectException(\Error::class);
|
||||
$this->expectException(RuntimeException::class);
|
||||
saveWebhookPayload(entity: $entity, request: $request);
|
||||
}
|
||||
|
||||
@@ -311,7 +312,7 @@ class HelpersTest extends TestCase
|
||||
$this->assertSame($request->getAttributes(), $fromFile->getAttributes());
|
||||
$this->assertSame($request->getParsedBody(), $fromFile->getParsedBody());
|
||||
|
||||
$this->expectException(\Error::class);
|
||||
$this->expectException(RuntimeException::class);
|
||||
saveRequestPayload(request: $request);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user