Skip to content

Commit

Permalink
Merge pull request #25 from pelmered/feature/validation-tests
Browse files Browse the repository at this point in the history
Add and improve tests
  • Loading branch information
pelmered authored May 8, 2024
2 parents bd8a698 + 01270d1 commit 9dcc0d5
Show file tree
Hide file tree
Showing 19 changed files with 1,322 additions and 926 deletions.
1,658 changes: 800 additions & 858 deletions composer.lock

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/Exceptions/UnsupportedCurrency.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
namespace Pelmered\FilamentMoneyField\Exceptions;

class UnsupportedCurrency extends \RuntimeException
{
public function __construct(string $currencyCode)
{
parent::__construct('Currency not supported: ' . $currencyCode);
}
}
5 changes: 4 additions & 1 deletion src/FilamentMoneyFieldServiceProvider.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php
namespace Pelmered\FilamentMoneyField;

use Illuminate\Foundation\Application;
use Pelmered\FilamentMoneyField\Forms\Rules\MaxValueRule;
use Pelmered\FilamentMoneyField\Forms\Rules\MaxValueRule2;
use Spatie\LaravelPackageTools\Package;

class FilamentMoneyFieldServiceProvider extends \Spatie\LaravelPackageTools\PackageServiceProvider
Expand All @@ -13,7 +16,7 @@ public function configurePackage(Package $package): void
->hasConfigFile();
}

public function boot()
public function boot(): void
{
$this->publishes([
__DIR__ . '/../config/filament-money-field.php' => config_path('filament-money-field.php'),
Expand Down
48 changes: 8 additions & 40 deletions src/Forms/Components/MoneyInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
use Filament\Forms\Components\TextInput;
use Filament\Support\RawJs;
use Illuminate\Support\Facades\Config;
use Pelmered\FilamentMoneyField\Forms\Rules\MaxValueRule;
use Pelmered\FilamentMoneyField\Forms\Rules\MinValueRule;
use Pelmered\FilamentMoneyField\HasMoneyAttributes;
use Pelmered\FilamentMoneyField\MoneyFormatter;

class MoneyInput extends TextInput
{
use HasMoneyAttributes;


protected function setUp(): void
{
parent::setUp();
Expand Down Expand Up @@ -52,8 +55,7 @@ protected function prepare(): void
$symbolPlacement = Config::get('filament-money-field.form_currency_symbol_placement', 'before');

$getCurrencySymbol = function (MoneyInput $component) {
$formattingRules = MoneyFormatter::getFormattingRules($component->getLocale());
return $formattingRules->currencySymbol;
return MoneyFormatter::getFormattingRules($component->getLocale())->currencySymbol;
};

if ($symbolPlacement === 'before') {
Expand All @@ -70,49 +72,15 @@ protected function prepare(): void
}
}

public function minValue(mixed $min): static
public function minValue(mixed $value): static
{
$this->rule(static function (MoneyInput $component, mixed $state) use ($min) {
return function (string $attribute, mixed $value, \Closure $fail) use ($component, $state, $min) {

$currencyCode = $component->getCurrency();
$locale = $component->getLocale();

$minorValue = MoneyFormatter::parseDecimal(
$state,
$currencyCode,
$locale
);

if ($minorValue < $min) {
$fail('The :attribute must be greater than or equal to ' . MoneyFormatter::formatAsDecimal($min, $currencyCode, $locale) . '.');
}
};
});

$this->rule(new MinValueRule($value, $this));
return $this;
}

public function maxValue(mixed $max): static
public function maxValue(mixed $value): static
{
$this->rule(static function (MoneyInput $component) use ($max) {
return function (string $attribute, mixed $value, \Closure $fail) use ($component, $max) {

$currencyCode = $component->getCurrency();
$locale = $component->getLocale();

$minorValue = MoneyFormatter::parseDecimal(
$value,
$currencyCode,
$locale
);

if ($minorValue > $max) {
$fail('The :attribute must be less than or equal to ' . MoneyFormatter::formatAsDecimal($max, $currencyCode, $locale) . '.');
}
};
});

$this->rule(new MaxValueRule($value, $this));
return $this;
}
}
50 changes: 50 additions & 0 deletions src/Forms/Rules/MaxValueRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
namespace Pelmered\FilamentMoneyField\Forms\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Money\Exception\ParserException;
use Pelmered\FilamentMoneyField\Forms\Components\MoneyInput;
use Pelmered\FilamentMoneyField\MoneyFormatter;

class MaxValueRule implements ValidationRule
{
public function __construct(private int $max, private MoneyInput $component)
{}

public function validate(string $attribute, mixed $value, Closure $fail): void
{
$currencyCode = $this->component->getCurrency();
$locale = $this->component->getLocale();

try {
$minorValue = MoneyFormatter::parseDecimal(
$value,
$currencyCode,
$locale
);

if ($minorValue >= $this->max) {
$fail(
strtr(
'The {attribute} must be less than or equal to {value}.',
[
'{attribute}' => ucwords($this->component->getLabel()),
'{value}' => MoneyFormatter::formatAsDecimal($this->max, $currencyCode, $locale),
]
)
);
}
} catch (ParserException $parserException) {
$fail(
strtr(
'The {attribute} must be a valid numeric value.',
[
'{attribute}' => ucwords($this->component->getLabel()),
]
)
);
}

}
}
49 changes: 49 additions & 0 deletions src/Forms/Rules/MinValueRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
namespace Pelmered\FilamentMoneyField\Forms\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Money\Exception\ParserException;
use Pelmered\FilamentMoneyField\Forms\Components\MoneyInput;
use Pelmered\FilamentMoneyField\MoneyFormatter;

readonly class MinValueRule implements ValidationRule
{
public function __construct(private int $min, private MoneyInput $component)
{}

public function validate(string $attribute, mixed $value, Closure $fail): void
{
$currencyCode = $this->component->getCurrency();
$locale = $this->component->getLocale();

try {
$minorValue = MoneyFormatter::parseDecimal(
$value,
$currencyCode,
$locale
);

if ($minorValue <= $this->min) {
$fail(
strtr(
'The {attribute} must be at least {value}.',
[
'{attribute}' => ucwords($this->component->getLabel()),
'{value}' => MoneyFormatter::formatAsDecimal($this->min, $currencyCode, $locale),
]
)
);
}
} catch (ParserException $parserException) {
$fail(
strtr(
'The {attribute} must be a valid numeric value.',
[
'{attribute}' => ucwords($this->component->getLabel()),
]
)
);
}
}
}
7 changes: 4 additions & 3 deletions src/HasMoneyAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
use Filament\Infolists\Infolist;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Pelmered\FilamentMoneyField\Exceptions\UnsupportedCurrency;

trait HasMoneyAttributes
{
protected Currency $currency;
protected string $locale;
protected ?string $monetarySeparator = null;

protected function getCurrency(): Currency
public function getCurrency(): Currency
{
return $this->currency ?? $this->currency(config('filament-money-field.default_currency') ?? Infolist::$defaultCurrency)->getCurrency();
}

protected function getLocale(): string
public function getLocale(): string
{
return $this->locale ?? config('filament-money-field.default_locale');
}
Expand All @@ -28,7 +29,7 @@ public function currency(string|\Closure|null $currencyCode = null): static
$currencies = new ISOCurrencies();

if (!$currencies->contains($this->currency)) {
throw new \RuntimeException('Currency not supported: ' . $currencyCode);
throw new UnsupportedCurrency($currencyCode);
}

return $this;
Expand Down
2 changes: 1 addition & 1 deletion src/Infolists/Components/MoneyEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected function setUp(): void
$this->isMoney = true;
$this->numeric();

$this->formatStateUsing(function (MoneyEntry $component, $state): ?string {
$this->formatStateUsing(function (MoneyEntry $component, $state): string {
$currency = $component->getCurrency();
$locale = $component->getLocale();

Expand Down
9 changes: 8 additions & 1 deletion src/MoneyFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Pelmered\FilamentMoneyField;

use Money\Currencies\ISOCurrencies;
use Money\Exception\ParserException;
use Money\Formatter\IntlMoneyFormatter;
use Money\Parser\IntlLocalizedDecimalParser;
use Money\Money;
Expand Down Expand Up @@ -44,7 +45,11 @@ public static function parseDecimal($moneyString, Currency $currency, string $lo
$formattingRules = self::getFormattingRules($locale);
$moneyString = str_replace($formattingRules->groupingSeparator, '', $moneyString);

return $moneyParser->parse($moneyString, $currency)->getAmount();
try {
return $moneyParser->parse($moneyString, $currency)->getAmount();
} catch (ParserException $parserException) {
throw new ParserException('The value must be a valid numeric value.');
}
}

public static function getFormattingRules($locale): MoneyFormattingRules
Expand All @@ -60,10 +65,12 @@ public static function getFormattingRules($locale): MoneyFormattingRules
);
}

/*
public static function decimalToMoneyString($moneyString, $locale): string
{
return str_replace(',', '.', (string)$moneyString);
}
*/

private static function getNumberFormatter($locale, int $style): NumberFormatter
{
Expand Down
2 changes: 1 addition & 1 deletion src/Tables/Columns/MoneyColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protected function setUp(): void
$this->isMoney = true;
$this->numeric();

$this->formatStateUsing(function (MoneyColumn $column, $state): ?string {
$this->formatStateUsing(function (MoneyColumn $column, $state): string {
$currency = $column->getCurrency();
$locale = $column->getLocale();

Expand Down
50 changes: 50 additions & 0 deletions tests/Components/FormTestComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
namespace Pelmered\FilamentMoneyField\Tests\Components;


use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;
use Filament\Forms\Form;
use Pelmered\FilamentMoneyField\Forms\Components\MoneyInput;

class FormTestComponent extends Component implements HasForms
{
use InteractsWithForms;

public $data;
public $form;

public static function make(): static
{
return new static();
}


public function form(Form $form): Form
{
return $form
->schema([
MoneyInput::make('price')
->minValue(100)
->maxValue(1000)
]);
}

public function mount(): void
{
//$this->form->fill();
}

public function data($data): static
{
$this->data = $data;

return $this;
}

public function getData()
{
return $this->data;
}
}
43 changes: 43 additions & 0 deletions tests/Components/InfolistTestComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
namespace Pelmered\FilamentMoneyField\Tests\Components;


use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Infolists\Concerns\InteractsWithInfolists;
use Filament\Infolists\Contracts\HasInfolists;
use Filament\Infolists\Infolist;
use Livewire\Component;
use Filament\Forms\Form;
use Pelmered\FilamentMoneyField\Forms\Components\MoneyInput;
use Pelmered\FilamentMoneyField\Infolists\Components\MoneyEntry;

class InfolistTestComponent extends Component implements HasForms, HasInfolists
{
use InteractsWithForms;
use InteractsWithInfolists;

public static function make(): static
{
return new static();
}

public function infolist(Infolist $infolist): Infolist
{
return $infolist
->state([])
->schema([
MoneyEntry::make('amount')
->currency('SEK')
->locale('sv_SE')
->label('Amount'),
]);
}

/*
public function render(): View
{
return view('infolists.fixtures.actions');
}
*/
}
Loading

0 comments on commit 9dcc0d5

Please sign in to comment.