jooservices / exceptions
Shared exception contracts, context-aware bases, and secret redaction for the JOOservices ecosystem.
Requires
- php: ^8.5
Requires (Dev)
- captainhook/captainhook: ^5.24
- captainhook/plugin-composer: ^5.3
- laravel/pint: ^1.18
- phpmd/phpmd: ^2.15
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^13.0
- squizlabs/php_codesniffer: ^3.13.6 || ^4.0.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-04 21:39:37 UTC
README
The JOOservices Exceptions Library is a PHP 8.5+ foundational library providing shared exception contracts, context-aware base classes, and secret redaction for the JOOservices package ecosystem.
Warning
v4.0.0 is a complete ground-up rebuild and is not backward compatible
with earlier package lines. It starts a fresh Git history and has no
legacy shims or deprecation bridge.
Package name: jooservices/exceptions
Install
composer require jooservices/exceptions
Core Features
- Ecosystem-wide catching: root marker
JOOExceptionInterfacefor one catch clause across all packages. - SPL semantics:
AbstractJOORuntimeException(operational) andAbstractJOOLogicException(programmer errors). - Structured context: immutable, redacted diagnostic context on
AbstractContextAwareException,AbstractContextAwareLogicException, or via theHasExceptionContexttrait. - Stable error metadata:
errorCode()({package}.{domain}.{reason}),logLevel()(PSR-3 vocabulary),toLogArray()(versionedlog_schema). - Sensitive data redaction:
DefaultContextRedactor+CompositeContextRedactor::withExtraKeys(). - Framework decoupled: zero runtime dependencies.
Basic Usage
Catching ecosystem exceptions
// runnable use JOOservices\Exceptions\Contracts\JOOExceptionInterface; $caught = false; try { throw new class('demo') extends \RuntimeException implements JOOExceptionInterface {}; } catch (JOOExceptionInterface $exception) { $caught = $exception instanceof \Throwable; }
Declaring a package exception
use JOOservices\Exceptions\Base\AbstractJOORuntimeException; abstract class ClientException extends AbstractJOORuntimeException {}
Context-aware exceptions
// runnable use JOOservices\Exceptions\Base\AbstractContextAwareException; use JOOservices\Exceptions\Support\ErrorCode; use JOOservices\Exceptions\Support\ExceptionContext; use JOOservices\Exceptions\Support\LogLevel; final class HydrationException extends AbstractContextAwareException { public static function forField(string $path, string $expectedType): self { return (new self("Hydration failed for field '{$path}'")) ->withContext(['path' => $path, 'expectedType' => $expectedType]); } public function errorCode(): string { return 'dto.hydration.failed'; } public function logLevel(): string { return LogLevel::ERROR->value; } protected function copyWithContext(ExceptionContext $context): static { return new self($this->getMessage(), $this->getCode(), $this->getPrevious(), $context); } } $exception = HydrationException::forField('user.email', 'string'); // getContext() is always redacted before it reaches the logger $context = $exception->getContext(); $logPayload = $exception->toLogArray();
Redaction bootstrap
// runnable use JOOservices\Exceptions\Base\AbstractContextAwareException; use JOOservices\Exceptions\Support\CompositeContextRedactor; AbstractContextAwareException::setRedactor( CompositeContextRedactor::withExtraKeys(['national_id', 'ssn']), ); AbstractContextAwareException::removeRedactor();
Never put secrets in exception messages. Put diagnostics in context and rely on redaction.
Documentation
- Documentation Hub
- Architecture
- Quick Start
- Laravel Integration
- Risks and Gaps
- Changelog
- Workflow guide
- Contributing
- Security policy
- Support
- Governance
- Code of Conduct
Development
Everything runs under Docker (php:8.5-cli-bookworm). GitHub Actions uses
GitHub-hosted ubuntu-latest with the same Compose image via tools/ci/docker-compose:
make build # builds jooservices/exceptions:php85 (php:8.5-cli-bookworm + pcov) make install # composer install inside the container make lint # Pint (per preset) + PHPCS + PHPStan (level max) + PHPMD make test # PHPUnit, no coverage make test-coverage # PHPUnit with 100% statement coverage gate make docs-verify # README/docs code snippets must parse and run make check # lint + docs + tests make ci # the full local CI gate (lint + docs + coverage)
License
MIT — see LICENSE.