- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
207 lines
4.5 KiB
PHP
207 lines
4.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\ErrorBoundaries;
|
|
|
|
use Throwable;
|
|
|
|
/**
|
|
* Result wrapper for error boundary operations
|
|
*
|
|
* @template T
|
|
*/
|
|
final readonly class BoundaryResult
|
|
{
|
|
private function __construct(
|
|
private mixed $value,
|
|
private ?Throwable $error,
|
|
private bool $isSuccess,
|
|
private ?string $boundaryName = null
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Create successful result
|
|
*
|
|
* @template U
|
|
* @param U $value
|
|
* @return BoundaryResult<U>
|
|
*/
|
|
public static function success(mixed $value): self
|
|
{
|
|
return new self($value, null, true);
|
|
}
|
|
|
|
/**
|
|
* Create failed result
|
|
*
|
|
* @template U
|
|
* @param Throwable $error
|
|
* @param string|null $boundaryName
|
|
* @return BoundaryResult<U>
|
|
*/
|
|
public static function failure(Throwable $error, ?string $boundaryName = null): self
|
|
{
|
|
return new self(null, $error, false, $boundaryName);
|
|
}
|
|
|
|
/**
|
|
* Check if operation was successful
|
|
*/
|
|
public function isSuccess(): bool
|
|
{
|
|
return $this->isSuccess;
|
|
}
|
|
|
|
/**
|
|
* Check if operation failed
|
|
*/
|
|
public function isFailure(): bool
|
|
{
|
|
return ! $this->isSuccess;
|
|
}
|
|
|
|
/**
|
|
* Get the result value (only if successful)
|
|
*
|
|
* @return T
|
|
* @throws BoundaryFailedException
|
|
*/
|
|
public function getValue(): mixed
|
|
{
|
|
if (! $this->isSuccess) {
|
|
throw new BoundaryFailedException(
|
|
'Cannot get value from failed result',
|
|
$this->boundaryName ?? 'unknown',
|
|
$this->error
|
|
);
|
|
}
|
|
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Get the error (only if failed)
|
|
*/
|
|
public function getError(): ?Throwable
|
|
{
|
|
return $this->error;
|
|
}
|
|
|
|
/**
|
|
* Get boundary name
|
|
*/
|
|
public function getBoundaryName(): ?string
|
|
{
|
|
return $this->boundaryName;
|
|
}
|
|
|
|
/**
|
|
* Get value or return default if failed
|
|
*
|
|
* @param T $default
|
|
* @return T
|
|
*/
|
|
public function getValueOrDefault(mixed $default): mixed
|
|
{
|
|
return $this->isSuccess ? $this->value : $default;
|
|
}
|
|
|
|
/**
|
|
* Get value or execute fallback function if failed
|
|
*
|
|
* @param callable(): T $fallback
|
|
* @return T
|
|
*/
|
|
public function getValueOrElse(callable $fallback): mixed
|
|
{
|
|
return $this->isSuccess ? $this->value : $fallback();
|
|
}
|
|
|
|
/**
|
|
* Transform the result if successful
|
|
*
|
|
* @template U
|
|
* @param callable(T): U $mapper
|
|
* @return BoundaryResult<U>
|
|
*/
|
|
public function map(callable $mapper): self
|
|
{
|
|
if (! $this->isSuccess) {
|
|
return new self(null, $this->error, false, $this->boundaryName);
|
|
}
|
|
|
|
try {
|
|
$transformed = $mapper($this->value);
|
|
|
|
return new self($transformed, null, true, $this->boundaryName);
|
|
} catch (Throwable $e) {
|
|
return new self(null, $e, false, $this->boundaryName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Chain another operation if current result is successful
|
|
*
|
|
* @template U
|
|
* @param callable(T): BoundaryResult<U> $mapper
|
|
* @return BoundaryResult<U>
|
|
*/
|
|
public function flatMap(callable $mapper): self
|
|
{
|
|
if (! $this->isSuccess) {
|
|
return new self(null, $this->error, false, $this->boundaryName);
|
|
}
|
|
|
|
try {
|
|
return $mapper($this->value);
|
|
} catch (Throwable $e) {
|
|
return new self(null, $e, false, $this->boundaryName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute callback if result is successful
|
|
*
|
|
* @param callable(T): void $callback
|
|
* @return self
|
|
*/
|
|
public function onSuccess(callable $callback): self
|
|
{
|
|
if ($this->isSuccess) {
|
|
$callback($this->value);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Execute callback if result failed
|
|
*
|
|
* @param callable(Throwable): void $callback
|
|
* @return self
|
|
*/
|
|
public function onFailure(callable $callback): self
|
|
{
|
|
if (! $this->isSuccess && $this->error) {
|
|
$callback($this->error);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Convert to array representation
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'success' => $this->isSuccess,
|
|
'value' => $this->isSuccess ? $this->value : null,
|
|
'error' => $this->error?->getMessage(),
|
|
'boundary' => $this->boundaryName,
|
|
];
|
|
}
|
|
}
|