diff --git a/composer.json b/composer.json index 66656c4..8fdf06a 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "illuminate/container": "^10.0|^11.0", "illuminate/database": "^10.0|^11.0", "hashids/hashids": "^4.0|^5.0", - "whichbrowser/parser": "^2.1" + "whichbrowser/parser": "^2.1", + "ashallendesign/laravel-config-validator": "^2.6.1" }, "require-dev": { "mockery/mockery": "^1.0", diff --git a/src/Classes/Validation.php b/src/Classes/Validation.php index 0d870b3..2219e91 100644 --- a/src/Classes/Validation.php +++ b/src/Classes/Validation.php @@ -4,6 +4,9 @@ namespace AshAllenDesign\ShortURL\Classes; +use AshAllenDesign\ConfigValidator\Exceptions\InvalidConfigValueException; +use AshAllenDesign\ConfigValidator\Services\ConfigValidator; +use AshAllenDesign\ConfigValidator\Services\Rule; use AshAllenDesign\ShortURL\Exceptions\ValidationException; class Validation @@ -12,57 +15,33 @@ class Validation * Validate all the config related to the library. * * @throws ValidationException + * @throws InvalidConfigValueException */ public function validateConfig(): bool { - return $this->validateKeyLength() - && $this->validateTrackingOptions() - && $this->validateDefaultRouteOption() - && $this->validateKeySalt() - && $this->validateEnforceHttpsOption() - && $this->validateForwardQueryParamsOption() - && $this->validateDefaultUrl(); - } - - /** - * Validate that the URL Length parameter specified in the config is an integer - * that is above 0. - * - * @throws ValidationException - */ - protected function validateKeyLength(): bool - { - $urlLength = config('short-url.key_length'); - - if (! is_int($urlLength)) { - throw new ValidationException('The config URL length is not a valid integer.'); - } - - if ($urlLength < 3) { - throw new ValidationException('The config URL length must be 3 or above.'); - } - - return true; - } - - /** - * Assert that the key salt provided in the config is valid. - * - * @throws ValidationException - */ - protected function validateKeySalt(): bool - { - $keySalt = config('short-url.key_salt'); - - if (! is_string($keySalt)) { - throw new ValidationException('The config key salt must be a string.'); - } - - if (! strlen($keySalt)) { - throw new ValidationException('The config key salt must be at least 1 character long.'); + $validator = app(ConfigValidator::class); + + $passes = $validator + ->throwExceptionOnFailure(false) + ->runInline([ + 'short-url' => [ + ...$this->validateTrackingOptions(), + Rule::make('key_length')->rules(['required', 'integer', 'min:3']), + Rule::make('key_salt')->rules(['required', 'string']), + Rule::make('disable_default_route')->rules(['required', 'boolean']), + Rule::make('enforce_https')->rules(['required', 'boolean']), + Rule::make('forward_query_params')->rules(['required', 'boolean']), + Rule::make('default_url')->rules(['nullable', 'string']), + ], + ]); + + if (! $passes) { + $validationMessage = $validator->errors()[array_key_first($validator->errors())][0]; + + throw new ValidationException($validationMessage); } - return true; + return $passes; } /** @@ -70,79 +49,19 @@ protected function validateKeySalt(): bool * * @throws ValidationException */ - protected function validateTrackingOptions(): bool - { - $trackingOptions = config('short-url.tracking'); - - if (! is_bool($trackingOptions['default_enabled'])) { - throw new ValidationException('The default_enabled config variable must be a boolean.'); - } - - foreach ($trackingOptions['fields'] as $trackingOption => $value) { - if (! is_bool($value)) { - throw new ValidationException('The '.$trackingOption.' config variable must be a boolean.'); - } - } - - return true; - } - - /** - * Validate that the disable_default_route option is a boolean. - * - * @throws ValidationException - */ - protected function validateDefaultRouteOption(): bool - { - if (! is_bool(config('short-url.disable_default_route'))) { - throw new ValidationException('The disable_default_route config variable must be a boolean.'); - } - - return true; - } - - /** - * Validate that the enforce_https option is a boolean. - * - * @throws ValidationException - */ - protected function validateEnforceHttpsOption(): bool - { - if (! is_bool(config('short-url.enforce_https'))) { - throw new ValidationException('The enforce_https config variable must be a boolean.'); - } - - return true; - } - - /** - * Validate that the forward query params option is a boolean. - * - * @throws ValidationException - */ - protected function validateForwardQueryParamsOption(): bool + protected function validateTrackingOptions(): array { - if (! is_bool(config('short-url.forward_query_params'))) { - throw new ValidationException('The forward_query_params config variable must be a boolean.'); - } + $trackingOptions = config('short-url.tracking.fields'); - return true; - } - - /** - * Validate that the default URL is a valid string or null. - * - * @throws ValidationException - */ - protected function validateDefaultUrl(): bool - { - $defaultUrl = config('short-url.default_url'); - $isValid = is_string($defaultUrl) || is_null($defaultUrl); + $rules = [ + Rule::make('tracking.default_enabled')->rules(['required', 'boolean']), + ]; - if (! $isValid) { - throw new ValidationException('The default_url config variable must be a string or null.'); + foreach ($trackingOptions as $trackingOption => $value) { + $rules[] = Rule::make('tracking.fields.'.$trackingOption) + ->rules(['required', 'boolean']); } - return true; + return $rules; } } diff --git a/src/Facades/ShortURL.php b/src/Facades/ShortURL.php index 973baee..c7b594b 100644 --- a/src/Facades/ShortURL.php +++ b/src/Facades/ShortURL.php @@ -1,5 +1,7 @@ expectException(ValidationException::class); - $this->expectExceptionMessage('The config URL length is not a valid integer.'); + $this->expectExceptionMessage('The short-url.key_length field must be an integer.'); Config::set('short-url.key_length', 'INVALID'); diff --git a/tests/Unit/Classes/ResolverTest.php b/tests/Unit/Classes/ResolverTest.php index 4abcba3..343d24f 100644 --- a/tests/Unit/Classes/ResolverTest.php +++ b/tests/Unit/Classes/ResolverTest.php @@ -91,7 +91,7 @@ public static function trackingFieldsProvider(): array public function exception_is_thrown_in_the_constructor_if_the_config_variables_are_invalid(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The config URL length is not a valid integer.'); + $this->expectExceptionMessage('The short-url.key_length field must be an integer.'); Config::set('short-url.key_length', 'INVALID'); diff --git a/tests/Unit/Classes/ValidationTest.php b/tests/Unit/Classes/ValidationTest.php index 45c726b..e44d32b 100644 --- a/tests/Unit/Classes/ValidationTest.php +++ b/tests/Unit/Classes/ValidationTest.php @@ -14,7 +14,7 @@ final class ValidationTest extends TestCase public function exception_is_thrown_if_the_key_length_is_not_an_integer(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The config URL length is not a valid integer.'); + $this->expectExceptionMessage('The short-url.key_length field must be an integer.'); Config::set('short-url.key_length', 'INVALID'); @@ -26,7 +26,7 @@ public function exception_is_thrown_if_the_key_length_is_not_an_integer(): void public function exception_is_thrown_if_the_key_length_is_below_3(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The config URL length must be 3 or above.'); + $this->expectExceptionMessage('The short-url.key_length field must be at least 3.'); Config::set('short-url.key_length', 2); @@ -38,7 +38,7 @@ public function exception_is_thrown_if_the_key_length_is_below_3(): void public function exception_is_thrown_if_the_default_enabled_variable_is_not_a_boolean(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The default_enabled config variable must be a boolean.'); + $this->expectExceptionMessage('The short-url.tracking.default_enabled field must be true or false.'); Config::set('short-url.tracking.default_enabled', 'INVALID'); @@ -50,7 +50,7 @@ public function exception_is_thrown_if_the_default_enabled_variable_is_not_a_boo public function exception_is_thrown_if_any_of_the_tracking_options_are_not_null(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The ip_address config variable must be a boolean.'); + $this->expectExceptionMessage('The short-url.tracking.fields.ip_address field must be true or false.'); Config::set('short-url.tracking.fields.ip_address', 'INVALID'); @@ -62,7 +62,7 @@ public function exception_is_thrown_if_any_of_the_tracking_options_are_not_null( public function exception_is_thrown_if_the_disable_default_route_option_is_not_a_boolean(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The disable_default_route config variable must be a boolean.'); + $this->expectExceptionMessage('The short-url.disable_default_route field must be true or false.'); Config::set('short-url.disable_default_route', 'INVALID'); @@ -74,7 +74,7 @@ public function exception_is_thrown_if_the_disable_default_route_option_is_not_a public function exception_is_thrown_if_the_key_salt_is_not_a_string(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The config key salt must be a string.'); + $this->expectExceptionMessage('The short-url.key_salt field must be a string.'); Config::set('short-url.key_salt', true); @@ -86,7 +86,7 @@ public function exception_is_thrown_if_the_key_salt_is_not_a_string(): void public function exception_is_thrown_if_the_key_salt_is_less_than_one_character_long(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The config key salt must be at least 1 character long.'); + $this->expectExceptionMessage('The short-url.key_salt field is required.'); Config::set('short-url.key_salt', ''); @@ -98,7 +98,7 @@ public function exception_is_thrown_if_the_key_salt_is_less_than_one_character_l public function exception_is_thrown_if_the_enforce_https_variable_is_not_a_boolean(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The enforce_https config variable must be a boolean.'); + $this->expectExceptionMessage('The short-url.enforce_https field must be true or false.'); Config::set('short-url.enforce_https', 'INVALID'); @@ -110,7 +110,7 @@ public function exception_is_thrown_if_the_enforce_https_variable_is_not_a_boole public function exception_is_thrown_if_the_forward_query_params_variable_is_not_a_boolean(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The forward_query_params config variable must be a boolean.'); + $this->expectExceptionMessage('The short-url.forward_query_params field must be true or false.'); Config::set('short-url.forward_query_params', 'INVALID'); @@ -122,7 +122,7 @@ public function exception_is_thrown_if_the_forward_query_params_variable_is_not_ public function exception_is_thrown_if_the_default_url_is_not_a_string(): void { $this->expectException(ValidationException::class); - $this->expectExceptionMessage('The default_url config variable must be a string or null.'); + $this->expectExceptionMessage('The short-url.default_url field must be a string.'); Config::set('short-url.default_url', true);