frootbox / exceptions
Frootbox Exceptions
README
Small semantic exception package for Frootbox applications and libraries.
The package provides shared exception classes for common application states such as missing input, invalid input, missing resources, access denial, and runtime errors. These exceptions are intentionally transport-neutral: application code can throw them without knowing whether the error is later rendered as HTML, JSON, CLI output, or something else.
Installation
composer require frootbox/exceptions
Basic Usage
use Frootbox\Exceptions\InputMissing; use Frootbox\Exceptions\NotFound; if (empty($payload['email'])) { throw new InputMissing('Email is required.'); } if ($customer === null) { throw new NotFound('Customer not found.'); }
Every exception extends Frootbox\Exceptions\BaseException, which extends PHP's native Exception.
Exception Classes
| Exception | Intended meaning | HTTP status |
|---|---|---|
AccessDenied |
Authenticated actor is not allowed to perform the action | 403 |
ClassMissing |
Required PHP class is missing | 500 |
ConfigurationMissing |
Required configuration value is missing | 400 |
InputInvalid |
Provided input is present but invalid | 400 |
InputMissing |
Required input value is missing | 400 |
NotFound |
Requested resource or database row does not exist | 404 |
NotLoggedIn |
Authentication is required | 401 |
ParameterMissing |
Required parameter is missing | 400 |
PermissionDenied |
Actor has insufficient permission | 403 |
ResourceInvalid |
Resource exists but cannot be used as requested | 400 |
ResourceMissing |
Required resource is missing | 404 |
RuntimeError |
Internal application/runtime failure | 500 |
HTTP Boundary Contract
Exceptions also implement:
Frootbox\Exceptions\Interfaces\HttpException
This interface exposes metadata for framework or adapter packages that need to render an error at an HTTP boundary:
public function getHttpStatusCode(): int; public function getErrorCode(): string; public function hasPublicMessage(): bool;
Example mapper:
use Frootbox\Exceptions\Interfaces\HttpException; try { $response = $controller->execute(); } catch (HttpException $exception) { http_response_code($exception->getHttpStatusCode()); header('Content-Type: application/json; charset=utf-8'); echo json_encode([ 'error' => [ 'code' => $exception->getErrorCode(), 'message' => $exception->hasPublicMessage() ? $exception->getMessage() : 'Unexpected API error.', ], ]); exit; }
Transport packages such as REST servers should depend on this interface instead of matching every concrete exception class individually.
Error Codes
Each exception exposes a stable machine-readable code through getErrorCode().
(new NotFound('Customer not found.'))->getErrorCode(); // not_found
If a concrete exception does not define a custom code, BaseException derives one from the class name.
Public Messages
Most domain and validation exceptions expose their message publicly. Internal failures such as RuntimeError and ClassMissing mark their message as non-public:
$exception->hasPublicMessage(); // false
HTTP renderers should respect this and replace the message with a generic one.
Properties
All exceptions accept optional properties for structured context:
throw new InputMissing(properties: [ 'email' ]);
The properties can be read with:
$exception->getProperties();
InputMissing keeps the existing legacy behavior: when no message is provided but properties are present, its message becomes Field.
Translated Messages
toString() builds a translation key compatible with Frootbox translators:
$exception->toString($translator);
If no translation is found, it falls back to the explicit exception message.