Skip to content

Commit

Permalink
[feature/validation-wrapping] Refactor ValidationExceptionBuilder ins…
Browse files Browse the repository at this point in the history
…tantiation and API

Replaced `message()` method with `make()` to standardize instantiation. Introduced `withMessage()` for setting custom messages. Updated documentation and tests to reflect these changes. Added default message handling and improved flexibility in redirect logic.
  • Loading branch information
midnite81 committed Sep 5, 2024
1 parent b239d7c commit cc150b8
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 21 deletions.
52 changes: 43 additions & 9 deletions docs/Validation/ValidationExceptionBuilder.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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.
Expand Down Expand Up @@ -83,15 +107,15 @@ 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();
```

### Custom Redirect with Query Parameters

```php
ValidationExceptionBuilder::message('Invalid input')
ValidationExceptionBuilder::make('Invalid input')
->redirectTo('/users')
->withQueryParameters(['sort' => 'name', 'order' => 'asc'])
->throwException();
Expand All @@ -100,15 +124,15 @@ ValidationExceptionBuilder::message('Invalid input')
### Using Named Routes

```php
ValidationExceptionBuilder::message('Access denied')
ValidationExceptionBuilder::make('Access denied')
->redirectRoute('dashboard', ['user' => $userId])
->throwException();
```

### Flashing Messages

```php
ValidationExceptionBuilder::message('Form submission failed')
ValidationExceptionBuilder::make('Form submission failed')
->redirectBack()
->flash('Please correct the errors and try again.', 'warning')
->throwException();
Expand All @@ -119,7 +143,7 @@ ValidationExceptionBuilder::message('Form submission failed')
```php
$someCondition = true;

ValidationExceptionBuilder::message('Conditional error')
ValidationExceptionBuilder::make('Conditional error')
->redirectBack()
->throwExceptionIf($someCondition);
```
Expand All @@ -129,18 +153,28 @@ ValidationExceptionBuilder::message('Conditional error')
```php
class MyCustomException extends Exception {}

ValidationExceptionBuilder::message('Something went wrong')
ValidationExceptionBuilder::make('Something went wrong')
->withException(MyCustomException::class)
->throwException();
```

### 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();
```
30 changes: 26 additions & 4 deletions src/Validation/ValidationExceptionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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.
*
Expand Down Expand Up @@ -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;
}

Expand Down
124 changes: 116 additions & 8 deletions tests/Validation/ValidationExceptionBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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');
});

0 comments on commit cc150b8

Please sign in to comment.