diff --git a/docs/Validation/ValidationExceptionBuilder.md b/docs/Validation/ValidationExceptionBuilder.md index a1eb7d6..691685b 100644 --- a/docs/Validation/ValidationExceptionBuilder.md +++ b/docs/Validation/ValidationExceptionBuilder.md @@ -11,7 +11,7 @@ Here's a quick example of how to use the `ValidationExceptionBuilder`: ```php use Midnite81\Core\Validation\ValidationExceptionBuilder; -ValidationExceptionBuilder::message('Invalid input') +ValidationExceptionBuilder::make('Invalid input') ->redirectTo('/form') ->flash('Please correct the errors and try again.') ->throwException(); @@ -20,16 +20,40 @@ ValidationExceptionBuilder::message('Invalid input') This will throw a `ValidationException` with the message "Invalid input", redirect the user to '/form', and flash a message to the session. +## Instantiation + +You can create a `ValidationExceptionBuilder` instance in two ways: + +1. Using the static `make()` method: + ```php + $builder = ValidationExceptionBuilder::make('Custom message'); + ``` + +2. Direct instantiation: + ```php + $builder = new ValidationExceptionBuilder('Custom message'); + ``` + +If no message is provided, a default message will be used: "There is an error in your form". + ## API Reference ### Static Methods +#### `make(string $message = ''): self` + +Create a new ValidationExceptionBuilder instance with an optional error message. + #### `message(string $message): self` -Create a new ValidationExceptionBuilder instance with the specified error message. +Alias for `make()`. Create a new ValidationExceptionBuilder instance with the specified error message. ### Instance Methods +#### `withMessage(string $message): self` + +Set a custom message for the exception. + #### `redirectTo(string $url): self` Set the URL to redirect to after validation failure. @@ -83,7 +107,7 @@ Throw the configured exception unless the given condition is true. ### Basic Validation Exception ```php -ValidationExceptionBuilder::message('The email is invalid') +ValidationExceptionBuilder::make('The email is invalid') ->redirectBack() ->throwException(); ``` @@ -91,7 +115,7 @@ ValidationExceptionBuilder::message('The email is invalid') ### Custom Redirect with Query Parameters ```php -ValidationExceptionBuilder::message('Invalid input') +ValidationExceptionBuilder::make('Invalid input') ->redirectTo('/users') ->withQueryParameters(['sort' => 'name', 'order' => 'asc']) ->throwException(); @@ -100,7 +124,7 @@ ValidationExceptionBuilder::message('Invalid input') ### Using Named Routes ```php -ValidationExceptionBuilder::message('Access denied') +ValidationExceptionBuilder::make('Access denied') ->redirectRoute('dashboard', ['user' => $userId]) ->throwException(); ``` @@ -108,7 +132,7 @@ ValidationExceptionBuilder::message('Access denied') ### Flashing Messages ```php -ValidationExceptionBuilder::message('Form submission failed') +ValidationExceptionBuilder::make('Form submission failed') ->redirectBack() ->flash('Please correct the errors and try again.', 'warning') ->throwException(); @@ -119,7 +143,7 @@ ValidationExceptionBuilder::message('Form submission failed') ```php $someCondition = true; -ValidationExceptionBuilder::message('Conditional error') +ValidationExceptionBuilder::make('Conditional error') ->redirectBack() ->throwExceptionIf($someCondition); ``` @@ -129,7 +153,7 @@ ValidationExceptionBuilder::message('Conditional error') ```php class MyCustomException extends Exception {} -ValidationExceptionBuilder::message('Something went wrong') +ValidationExceptionBuilder::make('Something went wrong') ->withException(MyCustomException::class) ->throwException(); ``` @@ -137,10 +161,20 @@ ValidationExceptionBuilder::message('Something went wrong') ### Using Exception Callback ```php -ValidationExceptionBuilder::message('Custom handling required') +ValidationExceptionBuilder::make('Custom handling required') ->withExceptionCallback(function ($message, $url, $errorBag) { // Custom logic here return new MyCustomException($message); }) ->throwException(); ``` + +### Direct Instantiation with Method Chaining + +```php +$builder = new ValidationExceptionBuilder(); +$builder->withMessage('Chained message') + ->redirectTo('/custom-page') + ->fragment('section1') + ->throwException(); +``` diff --git a/src/Validation/ValidationExceptionBuilder.php b/src/Validation/ValidationExceptionBuilder.php index 58bcabc..4bae0bf 100644 --- a/src/Validation/ValidationExceptionBuilder.php +++ b/src/Validation/ValidationExceptionBuilder.php @@ -39,12 +39,23 @@ class ValidationExceptionBuilder * * @param string $message The validation error message. */ - protected function __construct(string $message) + public function __construct(string $message = '') { - $this->message = $message; + $this->message = $message ?: 'There is an error in your form'; $this->redirectUrl = URL::previous(); } + /** + * Create a new instance of the class with an optional message. + * + * @param string $message The message to be associated with the new instance. + * @return self + */ + public static function make(string $message = ''): self + { + return new self($message); + } + /** * Create a new ValidationExceptionBuilder instance with the specified error message. * @@ -56,6 +67,18 @@ public static function message(string $message): self return new self($message); } + /** + * Set a custom message. + * + * @param string $message The message to set. + * @return self + */ + public function withMessage(string $message): self + { + $this->message = $message; + return $this; + } + /** * Set the URL to redirect to after validation failure. * @@ -271,11 +294,10 @@ protected function buildUrl(): string protected function createDefaultException(string $url): Exception { if ($this->exceptionClass === ValidationException::class) { - $exception = ValidationException::withMessages(['message' => $this->message])->redirectTo($url); + $exception = ValidationException::withMessages(['message' => [$this->message]])->redirectTo($url); if ($this->errorBag) { $exception->errorBag($this->errorBag); } - return $exception; } diff --git a/tests/Validation/ValidationExceptionBuilderTest.php b/tests/Validation/ValidationExceptionBuilderTest.php index 6e58f76..d75154d 100644 --- a/tests/Validation/ValidationExceptionBuilderTest.php +++ b/tests/Validation/ValidationExceptionBuilderTest.php @@ -19,6 +19,24 @@ expect($builder)->toBeInstanceOf(ValidationExceptionBuilder::class); }); +test('it creates a new instance using make method', function () { + $builder = ValidationExceptionBuilder::make('Test message'); + expect($builder)->toBeInstanceOf(ValidationExceptionBuilder::class); +}); + +test('it sets a custom message using withMessage method', function () { + $builder = ValidationExceptionBuilder::make()->withMessage('Custom message'); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception->getMessage())->toBe('Custom message'); +}); + test('it sets redirect URL', function () { $builder = ValidationExceptionBuilder::message('Test') ->redirectTo('http://example.com/redirect'); @@ -153,19 +171,109 @@ test('it throws exception conditionally with if', function () { $builder = ValidationExceptionBuilder::message('Test message'); - expect(fn () => $builder->throwExceptionIf(true))->toThrow(ValidationException::class); - expect(fn () => $builder->throwExceptionIf(false))->not->toThrow(ValidationException::class); + expect(fn() => $builder->throwExceptionIf(true))->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionIf(false))->not->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionIf(fn() => true))->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionIf(fn() => false))->not->toThrow(ValidationException::class); - expect(fn () => $builder->throwExceptionIf(fn () => true))->toThrow(ValidationException::class); - expect(fn () => $builder->throwExceptionIf(fn () => false))->not->toThrow(ValidationException::class); }); test('it throws exception conditionally with unless', function () { $builder = ValidationExceptionBuilder::message('Test message'); - expect(fn () => $builder->throwExceptionUnless(false))->toThrow(ValidationException::class); - expect(fn () => $builder->throwExceptionUnless(true))->not->toThrow(ValidationException::class); + expect(fn() => $builder->throwExceptionUnless(false))->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionUnless(true))->not->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionUnless(fn() => false))->toThrow(ValidationException::class) + ->and(fn() => $builder->throwExceptionUnless(fn() => true))->not->toThrow(ValidationException::class); + +}); + +test('it uses default message when not provided', function () { + $builder = ValidationExceptionBuilder::make(); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception->getMessage())->toBe('There is an error in your form'); +}); + +test('it resets route when redirectTo is called', function () { + $builder = ValidationExceptionBuilder::make() + ->redirectRoute('test.route') + ->redirectTo('http://example.com/redirect'); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception->redirectTo)->toBe('http://example.com/redirect'); +}); + +test('it resets route when redirectBack is called', function () { + $builder = ValidationExceptionBuilder::make() + ->redirectRoute('test.route') + ->redirectBack(); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception->redirectTo)->toBe('http://example.com/previous'); +}); + +test('it uses default message when directly instantiated without a message', function () { + $builder = new ValidationExceptionBuilder(); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception)->toBeInstanceOf(ValidationException::class) + ->and($exception->errors()['message'][0])->toBe('There is an error in your form'); +}); + +test('it uses custom message when directly instantiated with a message', function () { + $customMessage = 'This is a custom error message'; + $builder = new ValidationExceptionBuilder($customMessage); + + $exception = null; + try { + $builder->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } + + expect($exception)->toBeInstanceOf(ValidationException::class) + ->and($exception->errors()['message'][0])->toBe($customMessage); +}); + +test('it allows method chaining when directly instantiated', function () { + $builder = new ValidationExceptionBuilder(); + + $exception = null; + try { + $builder->withMessage('Chained message') + ->redirectTo('http://example.com/chained') + ->fragment('test') + ->throwException(); + } catch (ValidationException $e) { + $exception = $e; + } - expect(fn () => $builder->throwExceptionUnless(fn () => false))->toThrow(ValidationException::class); - expect(fn () => $builder->throwExceptionUnless(fn () => true))->not->toThrow(ValidationException::class); + expect($exception)->toBeInstanceOf(ValidationException::class) + ->and($exception->errors()['message'][0])->toBe('Chained message') + ->and($exception->redirectTo)->toBe('http://example.com/chained#test'); });