Skip to content

feat: currency field display consistency and constraint improvements#119

Merged
ManukMinasyan merged 18 commits into3.xfrom
feat/currency-field-improvements
Apr 10, 2026
Merged

feat: currency field display consistency and constraint improvements#119
ManukMinasyan merged 18 commits into3.xfrom
feat/currency-field-improvements

Conversation

@ManukMinasyan
Copy link
Copy Markdown
Collaborator

@ManukMinasyan ManukMinasyan commented Mar 19, 2026

Summary

  • CurrencyColumn: Dedicated table column with money formatting and configurable display type (symbol $1,200.50 or code USD 1,200.50)
  • CurrencyEntry: Dedicated infolist entry with money formatting and configurable display type
  • CurrencyComponent: Removed hardcoded minValue(0), default(0), and rules(['numeric', 'min:0']) — lets the capability system (MinValueCapability) handle these. formatStateUsing and dehydrateStateUsing now handle null and respect configured decimal places. NumberFormatter guarded with class_exists() for environments without ext-intl.
  • Currency settings: Configurable currency code, display type (symbol/code), and decimal places (0, 2, 3, 4) with ICU-powered currency list
  • Export transformer: CSV-safe export preserving meaningful precision (trims trailing zeros)

Behavior changes

Surface Before After
Table (symbol) Raw float 1234.56 $1,234.56
Table (code) Raw float 1234.56 USD 1,234.56
Infolist (symbol) Raw float 1234.56 $1,234.56
Infolist (code) Raw float 1234.56 USD 1,234.56
Form (new record) Pre-filled $0.00 Empty (null)
Form (negative values) Blocked by hardcoded min:0 Allowed unless MinValueCapability configured
Form (custom decimals) Always 100.00 Respects config e.g. 100.000
Export CSV Raw float 1234.56789 1234.56789 (preserves precision)

Test plan

  • 27 tests covering CurrencyColumn, CurrencyEntry, CurrencyComponent, export transformer, and CustomField currency helpers
  • Tests verify actual formatting behavior (isMoney/isNumeric/getPrefix assertions)
  • Full suite: 474 tests passing (7 pre-existing failures unrelated to this PR)
  • PHPStan: 0 errors
  • Pint: clean

Copilot AI review requested due to automatic review settings March 19, 2026 18:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves how the currency custom field type is presented across Filament surfaces (table, infolist, form) and adds CSV-safe export formatting, aiming for consistent currency display and better alignment with the validation capability system.

Changes:

  • Introduces dedicated CurrencyColumn (tables) and CurrencyEntry (infolists) using numeric formatting with a $ prefix.
  • Updates CurrencyComponent (forms) to remove hardcoded defaults/constraints and to better handle null + configurable decimal places.
  • Adds an export transformer to format currency values as CSV-safe strings with fixed 2-decimal precision.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Feature/Filament/Components/CurrencyFieldComponentsTest.php Adds feature tests covering the new column/entry/component behavior and export transformer formatting.
src/Filament/Integration/Components/Tables/Columns/CurrencyColumn.php New dedicated table column for currency with numeric formatting + $ prefix.
src/Filament/Integration/Components/Infolists/CurrencyEntry.php New dedicated infolist entry for currency with numeric formatting + $ prefix.
src/Filament/Integration/Components/Forms/CurrencyComponent.php Updates currency form input to respect decimal places and handle null without hardcoded min/default/rules.
src/FieldTypeSystem/Definitions/CurrencyFieldType.php Switches currency field type to the new Filament components and adds a CSV-safe export transformer.

ManukMinasyan and others added 8 commits March 19, 2026 23:04
validation_rules is nullable in the database. When a custom field has
null validation_rules, calling ->get() on null crashes. The nullsafe
operator ?-> was incorrectly removed by a PHPStan "fix".
Replace hardcoded $ prefix and validation_rules-based decimal places
with proper type-specific settings using the withSettings() API.

Currency fields now have 4 configurable settings:
- Currency code (50+ ISO 4217 currencies with searchable dropdown)
- Display type (symbol, narrow symbol, code, name)
- Decimal places (0 or 2 with live preview)
- Grouping (default thousands separator or none)

Display components use Filament's ->money() method instead of
->numeric()->prefix('$'). Form component derives the currency
symbol dynamically via NumberFormatter.

Backward compatible: getDecimalPlaces() falls back to
validation_rules then default, getCurrencyCode() falls back to
config default.
…selects

default() doesn't reliably hydrate existing records. afterStateHydrated
ensures correct values on both create and edit forms. Cast decimal_places
options to strings for select component compatibility.
the visibility check wrapper was overwriting any formatStateUsing set by
the column type (e.g. CurrencyColumn). now captures and re-evaluates the
existing formatter when the field is visible.
apply LocallyCalledStaticMethodToNonStaticRector,
EncapsedStringsToSprintfRector, and NewlineBeforeNewAssignSetRector
fixes flagged by CI.
- Use CurrencyFieldSettingsData with camelCase props and MapName mapper
  consistent with other data classes
- Hydrate settings via data class instead of raw array access
- Remove dead grouping setting (collected but never consumed)
- Reduce display_type to symbol/code (the two actually implemented)
- Remove obsolete HRK currency (replaced by EUR in 2023)
- Add 3 decimal places option for BHD/KWD/OMR currencies
- Stop hardcoding 2 decimal places in import/export transformers
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a dedicated Currency field presentation across Filament tables, infolists, and forms, and centralizes currency-related constraints (decimal places, currency code, display type) via per-field settings and validation.

Changes:

  • Added CurrencyColumn and CurrencyEntry using Filament money formatting for consistent display.
  • Updated CurrencyComponent to remove hardcoded defaults/constraints and to respect configured decimal places and null values.
  • Added currency settings DTO + CustomField helpers, plus currency-specific validation rules and export transformer behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/Feature/Filament/Components/CurrencyFieldComponentsTest.php Adds feature coverage for currency column/entry/component/export behavior.
src/Services/ValidationService.php Enforces currency decimal-places validation based on field settings.
src/Models/CustomField.php Adds currency helper accessors and legacy fallback handling.
src/Filament/Integration/Components/Tables/Columns/CurrencyColumn.php New table column for currency formatting.
src/Filament/Integration/Components/Infolists/CurrencyEntry.php New infolist entry for currency formatting.
src/Filament/Integration/Components/Forms/CurrencyComponent.php Updates form component formatting/dehydration and currency prefix logic.
src/Filament/Integration/Builders/TableBuilder.php Preserves existing column formatter when applying visibility wrapper.
src/FieldTypeSystem/Definitions/CurrencyFieldType.php Switches currency type to dedicated components and adds settings schema + import/export transformers.
src/Data/Settings/CurrencyFieldSettingsData.php New DTO for currency-specific settings hydration.
config/custom-fields.php Adds default currency code configuration.

- Use PHP intl ResourceBundle for dynamic, translatable currency list
- Auto-detect decimal places per currency from NumberFormatter (JPY=0, BHD=3)
- Filter historical/obsolete currencies automatically
- Locale-aware: currency names translate with app()->getLocale()
- Config override via custom-fields.currency.currencies for custom lists
- Remove 50-currency hardcoded array from CurrencyFieldType
- Honor display_type setting in CurrencyColumn and CurrencyEntry
  (symbol uses ->money(), code uses ->numeric() with code prefix)
- Guard NumberFormatter with class_exists() in CurrencyComponent
  and settings schema for environments without ext-intl
- Pass $record and $column context to existing formatter in TableBuilder
- Use $default parameter in CustomField::getDecimalPlaces()
- Add 4 decimal places option to settings UI
- Strengthen tests with isMoney/isNumeric/getPrefix assertions
- Replace static property caching with once() in CurrencyProvider
  for Octane/Swoole safety (no stale data across requests)
- Use Str::length() instead of strlen() for UTF-8 consistency
- Change $guarded from [] to ['id'] on CustomField model
- Extract duplicated display_type branching into
  ConfiguresCurrencyFormatting trait shared by CurrencyColumn
  and CurrencyEntry
@ManukMinasyan ManukMinasyan merged commit 4a48338 into 3.x Apr 10, 2026
3 checks passed
@ManukMinasyan ManukMinasyan deleted the feat/currency-field-improvements branch April 10, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants