Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Prices Laravel Package

mibo/prices

A Laravel package for handling prices and monetary values in your models. It offers a lightweight price object with formatting, arithmetic and currency helpers, keeping money logic consistent and testable across your application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin. Because the package has no dependents and negligible adoption, treat the version as volatile:

composer require mibo/prices

Before writing a line of application code, open composer.json in the vendor tree and confirm the PHP and illuminate/* constraints actually match your app. A package with zero dependents is rarely exercised against the Laravel version you're on, so run composer why-not mibo/prices if resolution fails, and commit composer.lock immediately.

Read these four things first, in order:

  1. vendor/mibo/prices/README.md — usage examples are the de facto spec here.
  2. vendor/mibo/prices/composer.json — service provider auto-discovery, supported Laravel versions.
  3. vendor/mibo/prices/src/ — the actual namespace, value objects, and service provider. With no docs ecosystem, the source is the documentation.
  4. vendor/mibo/prices/tests/ — if present, the tests show intended behaviour far more reliably than the README. If there are no tests, budget extra time for a spike.

Publish and migrate if the package ships config or schema:

php artisan vendor:publish --provider="Mibo\Prices\PriceServiceProvider"
php artisan migrate

Check whether publishing produced a config/prices.php (default currency, rounding mode, table names) or migrations (price tables, currency tables). If nothing publishes, the package is likely a pure value-object/formatting library and stores nothing itself.

First use case — the one to validate before anything else: attach a price to a model and render it. In php artisan tinker, create a price (or set an amount attribute on a model using the package's cast/accessor), then call whatever formatting method the source exposes and echo it. Confirm three things at once: the storage format in the database (raw integer or decimal?), the formatting output, and the currency default. Get this working in tinker before touching controllers — it surfaces config and cast issues in seconds rather than after a full request cycle.

Once that works, wrap it in a Blade component or an API resource so formatting lives in exactly one place across the app.

Implementation Patterns

Store minor units, format at the edges. The single most important pattern: persist amounts as integer minor units and treat the package's formatting layer as presentation-only. Never let a formatted string round-trip back into the database. If the package's value object exposes a ->amount() (raw) and a ->format() (display), enforce that split in code review — raw values go into calculations and JSON payloads, formatted values only into rendered HTML and emails.

Model integration via casts or accessors. The cleanest day-to-day usage is a cast or a small accessor so prices behave like first-class attributes:

protected $casts = [
    'price' => \Mibo\Prices\Casts\PriceCast::class, // verify exact FQCN in src/
];

If no cast exists, write a thin accessor/mutator pair in your own base model rather than sprinkling Price::make(...) calls through controllers. Keeping the package behind one accessor means you can swap it out later with a single diff.

Centralise formatting in a helper or Blade component. Price formatting rules change (locale, symbol placement, whether to show .00). Isolate them:

// app/Support/Money.php
public static function display($price, ?string $locale = null): string
{
    return $price->format($locale ?? app()->getLocale());
}

Then <x-price :value="$product->price" /> in views. This is also the seam where you inject a fallback if the package's formatter can't handle a currency you need.

Multi-currency: decide row-per-currency vs. conversion, and write it down. If the package supports per-currency price rows, model them as a relation (prices() hasMany with a currency column) and resolve with a scoped query. If it only converts from a base currency, cache the rate and never convert at render time in a loop. Either way, pin the decision in code comments — this is the assumption that bites hardest six months in.

Snapshot prices on orders. Never let an order total be computed by re-reading a live product price. Copy the resolved amount, currency, and any tax treatment onto the order line at checkout. Price packages change; historical invoices must not.

Resolution layer for tiered / list pricing. If you have customer groups, channels, or volume tiers, keep resolution in one service (PriceResolver), not in controllers:

$amount = $this->prices->forProduct($product)
    ->forCurrency($currency)
    ->forCustomer($customer)
    ->resolve();

Cache the resolved value per (product, currency, customer_group) key, and bust it on any price write. Wrap resolution in a single class even if the package offers fluent helpers — you want one place to add fallbacks and logging when a price is missing.

Testing. Use the package's factories if they ship; otherwise write your own. Assert on both layers: a feature test asserting the raw stored integer and a separate assertion on the rendered/formatted string. For anything financial, add one test per currency exponent you support (JPY, USD, KWD) — that's where formatters break.

Gotchas and Tips

Floats are the default failure mode. If the package's API accepts or returns float, convert at the boundary. Read a price into a float, sum ten of them, and you'll be off by a cent on some inputs. Keep everything integer-cents internally.

Currency exponents are not all 2. JPY has 0 decimals, KWD/BHD have 3. A formatter hard-coded for two decimals will silently misrender these. Test explicitly, and check the package's currency table (if it has one) for completeness before trusting it with anything exotic.

Locale vs. storage conflict. 1.234,56 and 1,234.56 are the same number. If the package's formatter is locale-aware, never pass already-formatted strings back into it. If it isn't locale-aware, you'll need to wrap it — check src/ for any locale or NumberFormatter usage early.

Rounding mode is a business decision, not a default. Confirm what the package does on half-cent values (round half up, half even, truncate) and that it matches your finance team's expectation. Where conversion or tax is involved, round once at the end, not per line item.

N+1 on price relations. If prices are a hasMany relation, $order->items->each->product->price will hammer the database. Eager load: Product::with('prices')->get(), and if you resolve per-currency, constrain the eager load rather than filtering in PHP.

Cache invalidation. Any price cache needs busting on model save/delete. Use an observer on the price model and key by all resolution dimensions — forgetting the customer-group dimension is the classic bug that shows one customer another's pricing.

Publish artifacts are not idempotent. If vendor:publish overwrites migrations you've already run, or the package's migrations collide with your table names, rename via the config before running migrate. Do this on a fresh branch and diff the schema.

Low-adoption risk management. With zero dependents, assume the package is unmaintained until proven otherwise. Concretely: fork it into your own VCS or lock the exact version, keep the usage surface to a handful of files (accessor, formatter helper, resolver), and add integration tests around it so a future replacement is a contained refactor rather than a rewrite. If it has no tests of its own, write the tests you'd want before you trust it with money.

Extension points to look for in src/: interfaces or contracts bound in the service provider (currency repository, formatter, rounding strategy), a config-driven model binding, and any Macroable traits. Binding your own implementation of a formatter interface is usually far cheaper than forking the whole package — check the provider's register()/bind() calls before you reach for a fork.

Debugging routine: when a formatted value looks wrong, dump the raw value from the database (DB::table(...)->first()), then dump() the value object in tinker to see what it actually holds, then check config/prices.php for the default currency and rounding. Ninety percent of "the package is broken" reports are a stale cached price or a config default the developer never read.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle