visiosoft/decimal-field_type
Adds a decimal field type to PyroCMS stream forms, giving developers precise decimal input handling for currency and other values requiring fixed-point precision in their Laravel-based applications.
This is a PyroCMS / Streams field type addon, not a standalone Laravel package. It only does anything inside a PyroCMS (or OpenClassify-style) application with pyrocms/streams installed. If you are on plain Laravel, this package is not for you.
Install
composer require visiosoft/decimal-field_type
# PyroCMS addons must be installed + published, not just required
php artisan addon:install visiosoft.field_type.decimal
php artisan addon:publish visiosoft.field_type.decimal
php artisan view:clear
If addon:install isn't available in your fork, install it from the control panel: Addons → Field Types → Decimal → Install. It will then appear in the Type dropdown when you create a field on any stream.
Where to look first
src/ — the field type class (DecimalFieldType). This is where getView(), getRules(), getConfig() and (if present) getMutator() live.resources/views/input.twig — the actual form input. Note: Twig, not Blade.resources/lang/en/addon.php — the name/description shown in the CP dropdown.composer.json — confirm "type": "pyrocms-field_type"; that's what makes it discoverable.First use case
Add a price field to a products stream:
Price, Slug: price, Type: Decimal{{ product.price }} in Twig, or {{ form('products').fields('price') }} inside your form markup.That's the entire happy path — it's a thin wrapper that renders a numeric input and stores a decimal. Treat it as plumbing, not a feature.
Declaring the field in code (migrations / seeders)
Prefer stream definitions in a seeder or migration over clicking through the CP, so environments stay reproducible:
$stream = $this->streams->streams()->findBySlug('products');
$stream->assignments()->create([
'stream_id' => $stream->id,
'field_slug' => 'price',
'field_name' => 'Price',
'field_type' => 'decimal',
'config' => ['decimals' => 2, 'default' => 0.00],
'required' => true,
'unique' => false,
]);
Keep field_type as the string decimal — that's the addon's slug and it must match the installed namespace (visiosoft.field_type.decimal).
Validation is layered, not built-in
Most field types only declare base rules. Add your own on the assignment / form level:
$form->add('price', 'decimal')->rules('required|numeric|min:0');
Don't assume min/max configured in the CP are enforced server-side — check getRules() in the source before you rely on it. For money, always add numeric explicitly.
Formatting belongs in a presenter, not the field
Store the raw decimal, format at display time:
class PricePresenter extends Presenter
{
public function format()
{
return number_format((float) $this->value, 2, '.', ',');
}
}
Twig: {{ product.price_view.format }}. This keeps you free to swap currency symbols, locales, or move to the visiosoft/currency-field_type later without a data migration.
Pair it with a currency field
The typical OpenClassify pattern is price (decimal) + currency (separate field type). Store the amount as a plain decimal, store the currency code beside it, and format on render. Never store pre-formatted strings — you lose sorting and aggregation.
Custom behaviour via a subclass
If you need a step size, a different input, or a different DB column type, don't edit the vendor directory. Extend it:
class MoneyFieldType extends \Visiosoft\DecimalFieldType\DecimalFieldType
{
protected $config = ['decimals' => 2];
public function getView()
{
return view('my_module::fields/money');
}
}
...then register your own addon with a distinct slug so both can coexist.
Querying / aggregation
Because it stores a decimal column, where('price', '>', 100) and sum('price') work as expected in the entry repository. The field is only special at the form/mutation layer — after that it's just a column.
src/ end to end before trusting it with money. It is probably ~40 lines.visiosoft.field_type.decimal::addon.name, you skipped addon:publish.resources/views/input.twig and pasting Blade directives will silently render nothing. Also run view:clear after every edit — PyroCMS caches aggressively.<input type="number"> submits 1.5 in a en-US browser but can submit 1,5 in some locales/hand-typed values. With numeric validation that fails opaquely. Either use a text input + explicit normalisation in getMutator(), or make sure your mutator casts defensively: (float) str_replace(',', '.', $value).getMutator() returns a string in the DB. Decimals come back as strings from Eloquent. Cast to float (or better, keep as string and use bcmath) wherever you do arithmetic — especially in totals and tax calculations.decimal(12,4), set the config before the assignment is created. Changing precision afterwards means a manual migration. Rounding silently truncates otherwise.default on a required field will break inserts. Set default in config if the column is NOT NULL.type matters. If you fork it, keep "type": "pyrocms-field_type" in composer.json and keep the resources/lang/*/addon.php keys — otherwise the addon disappears from the field type list with no error message."visiosoft/decimal-field_type": "1.0.*" rather than ^1.0 — a breaking Laravel/PyroCMS bump won't be signalled.FieldType base-class contract may have moved, and you'll get a fatal on the constructor rather than a clean composer conflict.php artisan tinker → app('streams.fields')->findBySlug('decimal') to confirm the addon registered, and check storage/logs/laravel.log after saving an entry — mutator exceptions are swallowed and surface as "field failed to save" in the CP.src/, rename, drop the composer dependency) is cheaper than waiting for upstream fixes.How can I help you explore Laravel packages today?