Domain Exceptions
Domain Exceptions represent business rule violations and domain-specific error conditions.
Characteristics
- Specific: One exception class per error type
- Contextual: Include relevant data for debugging
- Named constructors: Factory methods for clarity
- Domain language: Names reflect business concepts
Creating Exceptions
Extend AbstractDomainException with named constructors:
final class BookNotFoundException extends DomainException
{
public static function forId(IdInterface $id): self
{
return new self(
sprintf('Book with ID %s not found', $id->getValue())
);
}
}
final class InvalidIsbnException extends DomainException
{
public static function whenChecksumIsInvalid(): self
{
return new self('ISBN checksum is invalid');
}
}
Naming Conventions
| Pattern | Example | Use Case |
|---|---|---|
Invalid{VO}Exception | InvalidTitleException | Value Object validation |
{Entity}NotFoundException | BookNotFoundException | Entity not found |
{Entity}Not{State}Exception | BookNotAvailableException | Invalid state |
Throwing Exceptions
// In Value Objects
protected function validateRules(string $value): void
{
Assert::that($value)->notEmpty('Title cannot be empty');
}
// In Entities
public function borrow(): void
{
if ($this->status !== BookStatus::Available) {
throw BookNotAvailableException::forBook($this->id);
}
}
// In Repositories
public function getById(IdInterface $id): Book
{
return $this->findById($id) ?? throw BookNotFoundException::forId($id);
}
HTTP Status Mapping
| Exception Type | HTTP Status |
|---|---|
NotFoundException | 404 |
Invalid*Exception | 400 |
NotAllowedException | 403 |
AlreadyExistsException | 409 |