The JOOservices Exceptions Library is a PHP 8.5+ foundational library providing shared exception contracts, base exception classes, and structured context utilities across the JOOservices package ecosystem.
Package name: jooservices/exceptions
Latest stable release: v1.0.0 (see CHANGELOG)
composer require jooservices/exceptions- Ecosystem-Wide Catching: Root marker
JOOExceptionInterfacefor catch-all ecosystem handling. - SPL Semantics: Separate
AbstractJOORuntimeExceptionandAbstractJOOLogicExceptionbases. - Structured Context:
AbstractContextAwareException,AbstractContextAwareLogicException, andHasExceptionContext. - Stable Error Metadata:
errorCode(),logLevel()(LogLevelvocabulary),toLogArray(). - Sensitive Data Redaction:
DefaultContextRedactor+CompositeContextRedactor::withExtraKeys(). - Framework Decoupled: Zero runtime dependencies.
use JOOservices\Exceptions\Contracts\JOOExceptionInterface;
try {
$dto = UserDto::from($input);
} catch (JOOExceptionInterface $e) {
$logger->error($e->getMessage());
}use JOOservices\Exceptions\Base\AbstractJOORuntimeException;
abstract class ClientException extends AbstractJOORuntimeException {}use JOOservices\Exceptions\Base\AbstractContextAwareException;
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;
}
protected function copyWithContext(ExceptionContext $context): static
{
return new self($this->getMessage(), $this->getCode(), $this->getPrevious(), $context);
}
}$logger->log($exception->logLevel(), $exception->getMessage(), $exception->toLogArray());For logic / invariant failures with context, extend AbstractContextAwareLogicException the same way.
use JOOservices\Exceptions\Base\AbstractContextAwareException;
use JOOservices\Exceptions\Support\CompositeContextRedactor;
AbstractContextAwareException::setRedactor(
CompositeContextRedactor::withExtraKeys(['national_id', 'ssn']),
);Never put secrets in exception messages. Put diagnostics in context and rely on redaction.
When inheritance is blocked by a third-party base, use HasExceptionContext, implement copyWithContext(), and call initContext() in the constructor (fail-fast if omitted).
- Documentation Hub
- Changelog
- Installation
- Quick Start
- Laravel Integration
- Risks and Gaps
- AI Skills Usage
AGENTS.mdCLAUDE.md- AI Skills Map
- Canonical skills:
.github/skills/ - Adapters:
antigravity/prompts/,jetbrains/prompts/,.github/prompts/
composer lint
composer lint:all
composer docs:verify
composer test
composer test:coverage
composer check
composer ciApproved Git flow: feature/fix → develop; release/hotfix → master; tags from master.
- CI: security (
composer audit --locked), optional dependency-review, lint + docs snippet guard, PHPStan, PHPMD, 100% coverage tests, Codecov upload, optional SonarCloud (SONAR_TOKEN) - Codacy: free Analysis CLI → GitHub Code Scanning (optional
CODACY_PROJECT_TOKEN) - Fortify: free-trial capable; skips cleanly when credentials are absent
- Release: validate, GitHub release, Packagist update on
v*.*.*tags - PR Labeler / Semantic PR Title
- OpenSSF Scorecard / Secret Scanning (Gitleaks)
MIT — see LICENSE.