Download the PHP package nvl/primitives without Composer
On this page you can find all versions of the php package nvl/primitives. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download nvl/primitives
More information about nvl/primitives
Files in nvl/primitives
Package primitives
Short Description Immutable application value objects, exact money, validation, and ISO reference catalogs for Laravel
License MIT
Homepage https://github.com/nvl-laravel-suite/primitives
Informations about the package primitives
NVL Primitives — API and usage
Quickstart
Required NVL dependencies: nvl/core (^7.0). Use immutable value objects for validated scalar values. No package model factory or database is required; invalid programmer input retains its native exception category.
Use the getting-started guide provides a complete Comments host fixture; package archives retain their own local references.
For support, open an issue. For vulnerabilities, use private reporting. See Contributing.
See the installation and publishing guide for Composer setup, configuration, migration ownership, and agent skills.
Quick reference
| Item | Value |
|---|---|
| Installed through | composer require nvl/primitives:^7.0 |
| Module identifier | nvl/primitives |
| PHP namespace | Nvl\Primitives |
| Service provider | Nvl\Primitives\Providers\PrimitivesServiceProvider |
| Configuration | config/nvl-primitives.php |
Immutable application value objects, exact money, Eloquent casts, validation rules, currency conversion, and standards-backed reference catalogs for Laravel 13.
Purpose and boundaries
Primitives replaces the reusable parts of a traditional application “Core” module without becoming a second application framework. It owns:
- immutable value objects and canonical serialization;
- Eloquent casts for scalar, JSON, and monetary values;
- exact money arithmetic and an exchange-rate provider boundary;
- international phone and IBAN parsing backed by maintained registries;
- current ISO country, currency, and language catalogs;
- application locale, city, and bank option boundaries;
- native scalar, array, and domain-value contracts for application-owned projections.
It does not own users, settings, authorization, controllers, application routes, UI components, live exchange-rate HTTP clients, or a global cities/banks database.
Requirements and installation
- PHP 8.4+
- Laravel 13
ext-mbstring,ext-json, andext-ctype- optional
ext-intlfor locale-aware money formatting
Brick Money/Math and Carbon are required. Install the optional registries for the capabilities your application calls:
The package boots without these registries. Calling a dependent feature without its library throws an exception naming the package to install.
The package has no migrations and works without a database.
The translation tag publishes validation overrides to
lang/vendor/primitives while package defaults continue to load directly.
Value objects
| Value object | Canonical storage | Important behavior |
|---|---|---|
EmailAddress |
validated address string | normalizes the domain and masks for display |
Url |
absolute HTTP(S) string | normalizes scheme, host, and default ports; rejects credentials |
CountryCode |
ISO alpha-2 uppercase string | validates current country data |
CurrencyCode |
known ISO 4217 uppercase string | name, symbol, and fraction digits |
LocaleCode |
normalized BCP 47 core tag | enforces language, script, region, then variants |
PhoneNumber |
E.164 string | international parsing and formatting |
Iban |
electronic IBAN string | country format/checksum and masking |
DateTimeValue |
Y-m-d\TH:i:s.u\Z |
strict RFC 3339 input and canonical UTC output |
Percentage |
exact decimal ratio | exact percentage calculations |
Weight |
exact grams | kilograms, pounds, and ounces |
Length |
JSON metres | explicit scale and rounding for unit conversion |
Coordinates |
JSON string coordinates | WGS84 validation and distance |
PostalAddress |
JSON object | international components with an optional postal code |
Money |
{"minor":"…","currency":"…"} |
exact arithmetic and explicit conversion rounding |
Every primitive is immutable, JSON serializable, stringable, and type-safe for equality.
EmailAddress and Url follow PHP's native ASCII email/URL validation policy. They do not perform IDNA conversion or accept internationalized email local parts. Convert internationalized domains to reviewed punycode and percent-encode non-ASCII URL components in the host before construction; use an application-owned value policy when SMTPUTF8 is required.
Eloquent casts
Declare the value-object class directly:
Scalar primitives use one string/decimal column. Coordinates, PostalAddress, and default Money use JSON. Null remains null; malformed persisted values fail during hydration.
Scalar cast assignment and ValidPrimitive accept strings and integers, preserving exact values. Booleans and input floats are rejected before coercion. Database-hydrated floats remain supported by scalar casts where the primitive permits them; use string columns when exact decimal storage is required.
Money storage
Default JSON contains only integer minor units and currency:
For an explicitly fixed-currency schema:
Fixed modes accept a Money instance or a scalar representing that column's minor/decimal value. The cast rejects a different currency. An explicit Money::class.':json,EUR' currency is also enforced on both assignment and hydration. For variable-currency relational schemas, keep amount and currency in separate application-owned columns and construct Money at the model boundary.
SQLite hydrates DECIMAL columns as floating-point values. Decimal-mode casts normalize only those database-hydrated floats to the currency's fraction digits; assigning a float remains invalid. Prefer JSON or fixed-currency minor-unit storage when amounts may exceed SQLite's exact numeric range.
Exact money
Construct with decimal strings or integer minor units—never floats:
Currency is always explicit. An unrepresentable amount or operation throws unless a rounding mode is explicit. Arithmetic across currencies fails rather than converting implicitly. MoneyFormatter uses its injected configuration repository and falls back deterministically to amount currency when native ext-intl is unavailable.
Currency conversion
Configure deterministic rates:
Rates mean “target major units for one source major unit.” Every direction must be configured explicitly; inverse rates are never inferred. Rate values must be positive decimal strings, not floats or booleans. Optional as_of and max_age_seconds metadata must be supplied together; future, stale, malformed, and missing rates fail explicitly.
For production rates, implement and bind ExchangeRateProvider. It may use a database/API but must return an auditable decimal string and respect the optional effective date. Network calls do not belong in Money or CurrencyConverter.
Phones and IBANs
National phone input requires an explicit region or nvl-primitives.phone.default_region. Prefer an explicit request-specific region.
Locale and ISO codes
Locale tags support a language followed by an optional script, optional alpha/numeric region, and valid variant subtags. Extensions and private-use subtags are intentionally outside the package contract. Application-supported locale options come from Core’s Nvl\Support\Contracts\LocaleCatalog. Configure nvl-core.locales or bind that contract in the host.
Exact quantities and structured values
PostalAddress keeps components separate for country-specific presentation and permits countries without postal codes. DateTimeValue accepts only timezone-qualified RFC 3339 input with valid offset hours and minutes, preserves microseconds, and stores one canonical UTC value; convert only at display boundaries. Coordinate arrays accept numeric strings, integers, or floats and reject booleans. Email normalization preserves the complete local part, including quoted @ characters, and lowercases only the domain.
Url validates URL syntax and represents private or loopback hosts too. It supplies no DNS, redirect, network allowlist or SSRF protection; remote fetchers must enforce those policies separately. EmailAddress likewise does not establish deliverability or a public destination.
Laravel validation
Validation messages ship in English and Bulgarian and use Laravel's translation pipeline. Request validation improves messages, but domain code should still construct the primitive before persistence.
Reference catalogs
ReferenceCatalog returns bounded arrays with code, label, and scalar metadata keys:
Countries, currencies, and languages come from installed Symfony Intl standards data. Locale labels include script and region qualifiers so supported variants remain distinguishable. Cities and banks are deployment-specific, so configure small application lists:
Malformed catalog entries and limits outside 1..250 fail immediately. Large or dynamic datasets belong in an application service or repository. Primitives intentionally avoids mandatory reference tables and seeders.
Application projections
Use Money::toArray(), Length::toArray(), Coordinates::toArray(), and PostalAddress::toArray() at application boundaries. The application owns any DTOs, API resources, and generated TypeScript types. Keep vendor library objects out of JSON responses.
Adoption
- Replace existing money values only after auditing every float construction and making rounding explicit.
- Replace custom locale/country/currency enums or casts with validated codes.
- Replace phone/IBAN regex and checksum logic with registry-backed objects.
- Keep settings in
nvl/settings; Primitives does not own settings. - Retain application reference tables only when persistence, translation, or domain metadata is necessary.
- Replace suggestion controllers with application controllers calling
ReferenceCatalogor an application-owned directory.
Audit data before changing cast modes. JSON, decimal, and minor-unit money columns require an explicit migration.
Quality
The package gate runs Pint, PHPStan at maximum strictness, and isolated Testbench/Pest tests. Local Dagger verification additionally runs dependency analysis, Composer audit, integration tests and PHP 8.4/Laravel 13 release checks.
See CHANGELOG.md.
Supported PHP usage
The source @api declarations identify supported services, extension contracts, and value types. Public members marked @internal and untagged implementation types remain package-owned.
Testing your app
Immutable currencies, money, percentages, units, formatters, and catalogs are
direct APIs. This package has no Eloquent models or factories. Test calculations
with native values and substitute only the existing ExchangeRateProvider when
an application needs an exchange-rate boundary.
The configured default already uses a conditional transient binding and retains
host replacements. A host HTTP-backed rate provider can use Http::fake() in
its integration tests. Direct value tests and the injected rate test require no
new symmetry interface, package fake, or database fixture.
In Laravel application tests, register a native Mockery interface mock or a small
implementation with $this->app->instance(Contract::class, $substitute) before
resolving your application service. A host binding installed before package
registration is retained; later contract replacements affect subsequent
resolutions. Rebuild previously resolved host services after replacing their
dependencies. Mocks exercise your application orchestration;
package authorization, persistence, and external effects need real integration
tests.
ExchangeRateProvider already retains host bindings through bindIf. Immutable value construction and calculations remain direct; no new interface or factory is introduced.
Configuration and responses
Use nvl-primitives configuration and canonical package environment names. The consumer owns HTTP validation, response mapping and frontend types. Keep validated value objects and the existing exchange-rate provider boundary native.
Error codes and events
All recognized package failures implement Nvl\Support\Contracts\PackageException; only RespondableException opts into safe response metadata. Keep native PHP programmer errors and Laravel/SDK exceptions distinct. The optional PackageExceptionRenderer is registered by the host in withExceptions; it leaves unrelated, marker-only and non-JSON handling to the host. Its JSON envelope is {message:string, code:string, context:object}. Request locale is host-owned; diagnostics/previous exceptions are not public copy. Event schemas and source connections are documented in events.
The table lists enum discriminators, including any successful codes retained for compatibility. A code is not itself an HTTP status; the throwing exception's suggestedStatus() is authoritative, especially legacy/custom constructors. Empty context renders as {}; only documented JSON-safe context is presented.
| Code | Suggested status | Public context | Translation key |
|---|---|---|---|
operation_failed |
Exception-defined; see suggestedStatus() |
Declared safe scalar/array map; otherwise {} |
nvl-primitives::responsecode.operation_failed |
exchange_rate_stale |
409 | Declared safe scalar/array map; otherwise {} |
nvl-primitives::responsecode.exchange_rate_stale |
exchange_rate_unavailable |
422 | Declared safe scalar/array map; otherwise {} |
nvl-primitives::responsecode.exchange_rate_unavailable |
License
Released under the MIT License.
Shared service contracts, model extensions and composition apply alongside the package-specific rules above.
All versions of primitives with dependencies
brick/math Version ^0.14 || ^0.15 || ^0.16 || ^0.17 || ^0.18
brick/money Version ^0.11 || ^0.14
ext-ctype Version *
ext-filter Version *
ext-json Version *
ext-mbstring Version *
laravel/framework Version ^13.0
nesbot/carbon Version ^2.72 || ^3.0
nvl/core Version ^7.0