Skip to content

Commit

Permalink
Merge pull request #278 from ash-jc-allen/feature/config-validation
Browse files Browse the repository at this point in the history
Config validation updates
  • Loading branch information
ash-jc-allen authored Apr 26, 2024
2 parents 58e3f4f + 168392c commit 4e9a1df
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 128 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
149 changes: 34 additions & 115 deletions src/Classes/Validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -12,137 +15,53 @@ 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;
}

/**
* Validate that each of the tracking options are booleans.
*
* @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;
}
}
2 changes: 2 additions & 0 deletions src/Facades/ShortURL.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace AshAllenDesign\ShortURL\Facades;

use Illuminate\Support\Facades\Facade;
Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Classes/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ protected function setUp(): void
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');

Expand Down
2 changes: 1 addition & 1 deletion tests/Unit/Classes/ResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down
20 changes: 10 additions & 10 deletions tests/Unit/Classes/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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);

Expand All @@ -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');

Expand All @@ -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');

Expand All @@ -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');

Expand All @@ -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);

Expand All @@ -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', '');

Expand All @@ -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');

Expand All @@ -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');

Expand All @@ -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);

Expand Down

0 comments on commit 4e9a1df

Please sign in to comment.