Skip to content

Commit 65c8eb7

Browse files
authored
Merge pull request #4 from KaririCode-Framework/develop
refactor(input-exception): enhance InputException with new error type…
2 parents 56109df + e1fa5a7 commit 65c8eb7

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

src/Input/InputException.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ final class InputException extends AbstractException
1111
private const CODE_INVALID_FORMAT = 1901;
1212
private const CODE_MISSING_REQUIRED = 1902;
1313
private const CODE_EXCEEDS_MAX_LENGTH = 1903;
14+
private const CODE_INVALID_ARGUMENT = 1904;
15+
private const CODE_BELOW_MIN_LENGTH = 1905;
16+
private const CODE_OUT_OF_RANGE = 1906;
17+
private const CODE_INVALID_TYPE = 1907;
18+
private const CODE_INVALID_OPTION = 1908;
19+
private const CODE_DUPLICATE_ENTRY = 1909;
20+
private const CODE_INVALID_DATE = 1910;
21+
private const CODE_INVALID_CONFIG_PARAM = 1911;
1422

1523
public static function invalidFormat(string $field): self
1624
{
@@ -38,4 +46,99 @@ public static function exceedsMaxLength(string $field, int $maxLength): self
3846
"Field '{$field}' exceeds maximum length of {$maxLength}"
3947
);
4048
}
49+
50+
public static function invalidArgument(string $field, mixed $value, ?string $expectedType = null): self
51+
{
52+
$message = "Invalid argument for field '{$field}'. Received value: " . self::formatValue($value);
53+
if (null !== $expectedType) {
54+
$message .= ", expected type: {$expectedType}";
55+
}
56+
57+
return self::createException(
58+
self::CODE_INVALID_ARGUMENT,
59+
'INVALID_ARGUMENT',
60+
$message
61+
);
62+
}
63+
64+
public static function belowMinLength(string $field, int $minLength): self
65+
{
66+
return self::createException(
67+
self::CODE_BELOW_MIN_LENGTH,
68+
'BELOW_MIN_LENGTH',
69+
"Field '{$field}' is below minimum length of {$minLength}"
70+
);
71+
}
72+
73+
public static function outOfRange(string $field, $min, $max): self
74+
{
75+
return self::createException(
76+
self::CODE_OUT_OF_RANGE,
77+
'OUT_OF_RANGE',
78+
"Field '{$field}' is out of range. Must be between {$min} and {$max}"
79+
);
80+
}
81+
82+
public static function invalidType(string $field, string $expectedType): self
83+
{
84+
return self::createException(
85+
self::CODE_INVALID_TYPE,
86+
'INVALID_TYPE',
87+
"Field '{$field}' is of invalid type. Expected {$expectedType}"
88+
);
89+
}
90+
91+
public static function invalidOption(string $field, array $validOptions): self
92+
{
93+
$optionsString = implode(', ', $validOptions);
94+
95+
return self::createException(
96+
self::CODE_INVALID_OPTION,
97+
'INVALID_OPTION',
98+
"Invalid option for field '{$field}'. Valid options are: {$optionsString}"
99+
);
100+
}
101+
102+
public static function duplicateEntry(string $field, $value): self
103+
{
104+
return self::createException(
105+
self::CODE_DUPLICATE_ENTRY,
106+
'DUPLICATE_ENTRY',
107+
"Duplicate entry for field '{$field}' with value '{$value}'"
108+
);
109+
}
110+
111+
public static function invalidDate(string $field, string $format): self
112+
{
113+
return self::createException(
114+
self::CODE_INVALID_DATE,
115+
'INVALID_DATE',
116+
"Invalid date for field '{$field}'. Expected format: {$format}"
117+
);
118+
}
119+
120+
public static function invalidConfigParam(string $param, mixed $value, string $expectedDescription): self
121+
{
122+
$message = "Invalid configuration parameter '{$param}'. " .
123+
'Received value: ' . self::formatValue($value) .
124+
". Expected: {$expectedDescription}";
125+
126+
return self::createException(
127+
self::CODE_INVALID_CONFIG_PARAM,
128+
'INVALID_CONFIG_PARAM',
129+
$message
130+
);
131+
}
132+
133+
private static function formatValue(mixed $value): string
134+
{
135+
return match (true) {
136+
is_string($value) => "'{$value}'",
137+
is_bool($value) => $value ? 'true' : 'false',
138+
is_null($value) => 'null',
139+
is_array($value) => 'array',
140+
is_object($value) => get_class($value),
141+
default => (string) $value,
142+
};
143+
}
41144
}

tests/Input/InputExceptionTest.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,111 @@ public function testExceedsMaxLength(): void
4545
1903
4646
);
4747
}
48+
49+
public function testInvalidArgument(): void
50+
{
51+
$field = 'age';
52+
$value = 'not a number';
53+
$expectedType = 'integer';
54+
$exception = InputException::invalidArgument($field, $value, $expectedType);
55+
$this->assertExceptionStructure(
56+
$exception,
57+
'INVALID_ARGUMENT',
58+
"Invalid argument for field 'age'. Received value: 'not a number', expected type: integer",
59+
1904
60+
);
61+
}
62+
63+
public function testBelowMinLength(): void
64+
{
65+
$field = 'password';
66+
$minLength = 8;
67+
$exception = InputException::belowMinLength($field, $minLength);
68+
$this->assertExceptionStructure(
69+
$exception,
70+
'BELOW_MIN_LENGTH',
71+
"Field '{$field}' is below minimum length of {$minLength}",
72+
1905
73+
);
74+
}
75+
76+
public function testOutOfRange(): void
77+
{
78+
$field = 'rating';
79+
$min = 1;
80+
$max = 5;
81+
$exception = InputException::outOfRange($field, $min, $max);
82+
$this->assertExceptionStructure(
83+
$exception,
84+
'OUT_OF_RANGE',
85+
"Field '{$field}' is out of range. Must be between {$min} and {$max}",
86+
1906
87+
);
88+
}
89+
90+
public function testInvalidType(): void
91+
{
92+
$field = 'count';
93+
$expectedType = 'integer';
94+
$exception = InputException::invalidType($field, $expectedType);
95+
$this->assertExceptionStructure(
96+
$exception,
97+
'INVALID_TYPE',
98+
"Field '{$field}' is of invalid type. Expected {$expectedType}",
99+
1907
100+
);
101+
}
102+
103+
public function testInvalidOption(): void
104+
{
105+
$field = 'status';
106+
$validOptions = ['active', 'inactive', 'pending'];
107+
$exception = InputException::invalidOption($field, $validOptions);
108+
$this->assertExceptionStructure(
109+
$exception,
110+
'INVALID_OPTION',
111+
"Invalid option for field '{$field}'. Valid options are: active, inactive, pending",
112+
1908
113+
);
114+
}
115+
116+
public function testDuplicateEntry(): void
117+
{
118+
$field = 'email';
119+
$value = 'test@example.com';
120+
$exception = InputException::duplicateEntry($field, $value);
121+
$this->assertExceptionStructure(
122+
$exception,
123+
'DUPLICATE_ENTRY',
124+
"Duplicate entry for field '{$field}' with value '{$value}'",
125+
1909
126+
);
127+
}
128+
129+
public function testInvalidDate(): void
130+
{
131+
$field = 'birthdate';
132+
$format = 'Y-m-d';
133+
$exception = InputException::invalidDate($field, $format);
134+
$this->assertExceptionStructure(
135+
$exception,
136+
'INVALID_DATE',
137+
"Invalid date for field '{$field}'. Expected format: {$format}",
138+
1910
139+
);
140+
}
141+
142+
public function testInvalidConfigParam(): void
143+
{
144+
$param = 'timeout';
145+
$value = -1;
146+
$expectedDescription = 'a positive integer';
147+
$exception = InputException::invalidConfigParam($param, $value, $expectedDescription);
148+
$this->assertExceptionStructure(
149+
$exception,
150+
'INVALID_CONFIG_PARAM',
151+
"Invalid configuration parameter '{$param}'. Received value: -1. Expected: {$expectedDescription}",
152+
1911
153+
);
154+
}
48155
}

0 commit comments

Comments
 (0)