Skip to content

Commit

Permalink
added custom attribute and value names + beforeValidation callable
Browse files Browse the repository at this point in the history
  • Loading branch information
henzeb committed Apr 11, 2023
1 parent 609b6b5 commit f5eebdc
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to `Laravel Console Facade` will be documented in this file

## 1.18.0 - 2023-04-11

- added extra parameters for [validateWith](README.md#validation)
- added [beforeValidation](README.md#before-validation-callback)

## 1.17.0 - 2023-04-11

- allow sections without names
Expand Down
54 changes: 53 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,6 @@ you may want to give them different translations. Just add a second array
like you would do with Laravel's validation engine:

````php

Console::validateWith(
[
'id' => 'bail|int|exists:users',
Expand All @@ -412,6 +411,59 @@ Console::validateWith(
);
````

### attribute names

Laravel allows you to rename attributes.

````php
Console::validateWith(
[
'id' => 'bail|int|exists:users',
'--name' => 'string|min:2'
],
attributes: [
'id' => 'user id',
'--name' => 'name'
]
);
````

### value names

Just like attributes, you can also give certain values names.

Below we see an example where the accepted flag must be a form of `true`
when any gender is specified.

````php
Console::validateWith(
[
'--gender' =>'required|in:x,f,m',
'--accepted' => 'accepted_if:--gender,x,--gender,f,--gender,m',
],
valueNames: [
'--gender' => [
'm' => 'male',
'f' => 'female',
'x' => 'other gender'
]
]
);
````

### before validation callback

When you need access to the Validator instance before execution, you can use the
`beforeValidation` method.

````php
Console::beforeValidation(
function(Illuminate\Validation\Validator $validator){
// your logic
}
);
````

### Closure based commands

When running `ClosureCommands` defined with `Artisan::command()` it does not
Expand Down
38 changes: 33 additions & 5 deletions src/Concerns/ValidatesInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Henzeb\Console\Concerns;

use Closure;
use Illuminate\Contracts\Validation\Validator as ValidatorInstance;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\MessageBag;
use Symfony\Component\Console\Exception\InvalidArgumentException;
Expand All @@ -13,6 +14,9 @@ trait ValidatesInput
{
private array $rules = [];
private array $messages = [];
private array $attributes = [];
private array $valueNames = [];
private array $beforeValidation = [];
private string $command = 'default';

public function setCommandForValidation(string $command): void
Expand All @@ -36,10 +40,19 @@ function () {
)();
}

public function validateWith(array $rules, array $messages = []): void
public function validateWith(array $rules, array $messages = [], array $attributes = [], array $valueNames = []): void
{
$this->rules[$this->getCommandForValidation()] = $rules;
$this->messages[$this->getCommandForValidation()] = $messages;
$command = $this->getCommandForValidation();

$this->rules[$command] = $rules;
$this->messages[$command] = $messages;
$this->attributes[$command] = $attributes;
$this->valueNames[$command] = $valueNames;
}

public function beforeValidation(callable $beforeValidation): void
{
$this->beforeValidation[$this->getCommandForValidation()] = $beforeValidation;
}

private function getData(): array
Expand Down Expand Up @@ -75,10 +88,15 @@ public function validate(): void
$command = $this->getCommandForValidation();
$validator = Validator::make(
$this->getData(),
$this->rules[$command] ?? $this->rules['default'],
$this->messages[$command] ?? $this->messages['default']
$this->rules[$command] ?? [],
$this->messages[$command] ?? [],
$this->attributes[$command] ?? [],
);

$validator->setValueNames($this->valueNames[$command] ?? []);

$this->executeBeforeValidation($command, $validator);

if ($validator->fails()) {
$this->throwNiceException($validator->getMessageBag());
}
Expand Down Expand Up @@ -134,4 +152,14 @@ private function asOptionKey(string $name, InputDefinition $definition): string
$option->getShortcut() ? '|-' . $option->getShortcut() : ''
);
}

/**
* @param string $command
* @param ValidatorInstance $validator
* @return void
*/
public function executeBeforeValidation(string $command, ValidatorInstance $validator): void
{
($this->beforeValidation[$command] ?? fn() => null)($validator);
}
}
3 changes: 1 addition & 2 deletions src/Output/TailConsoleSectionOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ private function writeTail(string $message = '', bool $newline = false): void
$this->replace(
implode(
PHP_EOL, $content
) . ($newline ? PHP_EOL : ''),
false
) . ($newline ? PHP_EOL : '')
);
}
}
79 changes: 79 additions & 0 deletions tests/Unit/Console/Concerns/ValidatesInputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,59 @@ public function testArgumenthouldFailValidation()
}
}

public function testValidateWithAttributeRenaming()
{
$this->setParameters('{--arg_required=}', '--arg_required fail');

Console::validateWith(
[
'--arg_required' => 'size:7'
],
[],
[
'--arg_required' => 'required arg'
]
);

$this->assertTrue(Console::optionGiven('arg_required'));

$this->expectException(InvalidArgumentException::class);

try {
Console::validate();
} catch (InvalidArgumentException $exception) {
$this->assertStringContainsString('The required arg', $exception->getMessage());
throw $exception;
}
}

public function testValidateWithValueNames()
{
$this->setParameters('{--arg1=} {--arg2=}', '--arg1 aa');

Console::validateWith(
[
'--arg2' => 'required_if:--arg1,aa'
],
[],
[],
[
'--arg1' => [
'aa' => 'double-a'
]
]
);

$this->expectException(InvalidArgumentException::class);

try {
Console::validate();
} catch (InvalidArgumentException $exception) {
$this->assertStringContainsString('--arg1 is double-a', $exception->getMessage());
throw $exception;
}
}

public function testArgumentShouldNotValidateIfNotGiven()
{
$this->setParameters('{arg_required} {--arg_required}', '--arg_required');
Expand Down Expand Up @@ -189,4 +242,30 @@ public function testClosureWithoutValidationCommand()

Artisan::call('test:no-validation-rules', ['--test' => 'a']);
}

public function testBeforeValidationCallback()
{
$actual = false;

Console::beforeValidation(
function () use (&$actual) {
$actual = true;
}
);
Console::validateWith([
'--test' => 'string'
]);

Console::validate();

$this->assertTrue($actual);

$actual = false;

Console::setCommandForValidation('test');
Console::validate();

$this->assertFalse($actual);

}
}
2 changes: 1 addition & 1 deletion tests/Unit/Console/Output/ConsoleSectionOutputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function testShouldReturnProgressBar(): void

$output = $this->mock(ConsoleSectionOutput::class);
$output->shouldAllowMockingProtectedMethods();
$output->expects('contentEndsWithNewLine')->andReturn(false);
$output->expects('contentEndsWithNewLine')->andReturn(true);
(function () use ($outputStyle) {
$this->output = $outputStyle;
})->bindTo($output, ConsoleSectionOutput::class)();
Expand Down

0 comments on commit f5eebdc

Please sign in to comment.