I've a class rule:
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class DecimalRule implements ValidationRule
{
protected int $integerLength;
protected int $decimalLength;
public function __construct(int $integerLength, int $decimalLength)
{
$this->integerLength = $integerLength;
$this->decimalLength = $decimalLength;
}
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
ray($attribute, $value);
// Check if the value is a number
if (!is_numeric($value)) {
$fail("The {$attribute} must be a numeric value.");
return;
}
// Check the length of the integer part
$parts = explode('.', $value);
$integerPart = $parts[0];
$decimalPart = $parts[1] ?? '';
// Check the length of the integer part
if (strlen($integerPart) > $this->integerLength) {
$fail("The {$attribute} must have no more than {$this->integerLength} integer digits.");
return;
}
// Check the length of the decimal part
if (strlen($decimalPart) > $this->decimalLength) {
$fail("The {$attribute} must have no more than {$this->decimalLength} decimal digits.");
}
}
}
Unit testing
<?php
namespace Tests\Unit\Rules;
use App\Rules\DecimalRule;
use Tests\TestCase;
class DecimalRuleTest extends TestCase
{
/** @test */
function it_passes_with_valid_data()
{
$rule = new DecimalRule(9, 6);
$validator = $this->app['validator']->make(
['testAttribute' => '123456789.123456'],
['testAttribute' => $rule]
);
$this->assertFalse($validator->fails());
}
/** @test */
function it_fails_with_invalid_integer_length()
{
$rule = new DecimalRule(9, 6);
$validator = $this->app['validator']->make(
['testAttribute' => '1234567890.123456'],
['testAttribute' => $rule]
);
$this->assertTrue($validator->fails());
}
/** @test */
function it_fails_with_invalid_decimal_length()
{
$rule = new DecimalRule(9, 6);
$validator = $this->app['validator']->make(
['testAttribute' => '123456789.1234567'],
['testAttribute' => $rule]
);
$this->assertTrue($validator->fails());
}
/** @test */
function it_fails_if_number_is_greater()
{
$rule = new DecimalRule(9, 6);
$validator = $this->app['validator']->make(
['testAttribute' => '10000000000'],
['testAttribute' => $rule]
);
$this->assertTrue($validator->fails());
}
}
Work fine.
Now I have a Request class
<?php
namespace App\Http\Requests;
use App\Rules\DecimalRule;
use Bouncer;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
class CommandCenterHistoricalFactRequest extends FormRequest
{
public function authorize(): bool
{
return Auth::user()->isSuperAdmin() || Bouncer::is(Auth::user())->a('administrator');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
*/
public function rules(): array
{
return [
'globalSearch' => 'filled',
'download' => [
'filled',
'prohibits:perPage',
Rule::in(['xlsx', 'csv', 'ods', 'html', 'pdf']),
],
'filter.id' => 'integer|filled',
'filter.command_center_id' => 'int|filled|exists:command_centers,id',
'filter.eneact_kwh' => ['filled', new DecimalRule(9, 6)],
'filter.is_historical' => 'boolean|filled',
'filter.date' => 'filled|date_format:Y-m-d',
'page' => 'filled|int',
'perPage' => [
'int',
'filled',
'required_with:pag',
Rule::in([5, 10, 25, 50, 100, 500]),
],
];
}
}
And testing
<?php
namespace Tests\Feature\Http\Requests;
use App\Http\Requests\CommandCenterHistoricalFactRequest;
use Illuminate\Support\Facades\Validator;
use Tests\TestCase;
class CommandCenterHistoricalFactRequestTest extends TestCase
{
/** @test */
public function it_passes_with_valid_data_at_cc_historical_fact_request()
{
$validator = Validator::make([
'globalSearch' => 'example',
'download' => 'csv',
'filter.id' => 1,
'filter.command_center_id' => 1,
'filter.eneact_kwh' => 123.45,
'filter.is_historical' => true,
'filter.date' => '2023-05-09',
'page' => 1
], (new CommandCenterHistoricalFactRequest())->rules());
$this->assertFalse($validator->fails());
}
/** @test */
function it_fails_with_invalid_eneact_kwh_at_cc_historical_fact_request()
{
$validator = Validator::make([
'globalSearch' => 'example',
'download' => 'csv',
'filter.id' => 1,
'filter.command_center_id' => 1,
'filter.eneact_kwh' => 123.1234567,
'filter.is_historical' => true,
'filter.date' => '2023-05-09',
'page' => 1
], (new CommandCenterHistoricalFactRequest())->rules());
$this->assertTrue($validator->fails());
}
/** @test */
public function it_fails_with_invalid_data_at_cc_historical_fact_request()
{
$validator = Validator::make([
'globalSearch' => '',
'download' => 'invalid-format',
'filter.id' => 'string',
'filter.command_center_id' => 'string',
'filter.eneact_kwh' => 'invalid-number',
'filter.is_historical' => 'invalid-boolean',
'filter.date' => 'invalid-date',
'page' => 'invalid-page',
'perPage' => 999
], (new CommandCenterHistoricalFactRequest())->rules());
$this->assertTrue($validator->fails());
}
/** @test */
public function it_fails_with_invalid_eneact_kwh()
{
$validator = Validator::make([
'filter.eneact_kwh' => '10000000000.000001'
], (new CommandCenterHistoricalFactRequest())->rules());
ray($validator->messages());
$this->assertTrue($validator->fails());
}
}
Lates test it_fails_with_invalid_eneact_kwh fails.
Rule validate a bad value greater.
at tests/Feature/Http/Requests/CommandCenterHistoricalFactRequestTest.php:72
68▕ 'filter.eneact_kwh' => 123.1234567,
69▕ ], (new CommandCenterHistoricalFactRequest())->rules());
70▕
71▕ ray($validator->messages());
➜ 72▕ $this->assertTrue($validator->fails());
Desesperate