NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages

Values keep their real PHP type across write and read — no manual casting:

use RoundlyConsulting\Attributes\Facades\Attributes;

$attributes = Attributes::for($product);

$attributes->set('color', 'white');       // string
$attributes->set('rating', 5);            // int
$attributes->set('on_sale', true);        // bool
$attributes->set('price', 9.99);          // float
$attributes->set('tags', ['a', 'b']);     // array
$attributes->set('published_at', now());  // datetime

$attributes->get('rating');               // int(5)
$attributes->get('on_sale');              // true
$attributes->get('published_at');         // CarbonImmutable, in the app timezone

// Model shorthand — the same manager underneath
$product->attachAttribute('rating', 5);
$product->getAttachedAttributeValue('rating'); // int(5)

How types are stored

Without a definition, the type is inferred from the PHP value you pass and stored in value_type next to the value, which is kept as text:

PHP valuevalue_typeStored asRead back as
string (and anything else)stringthe stringstring
intinteger5 → 5 as textint
floatfloatthe shortest text that reads back as the same floatfloat
boolboolean1 or 0bool
arrayarrayJSONarray
DateTimeInterfacedatetimeISO-8601 string in UTCCarbonImmutable in the app timezone
nullstringSQL NULL (value_type is the defined type, if any)null

Datetimes are normalized to UTC, so one instant always has one stored string, and come back as the same instant in your app timezone. Floats keep their full precision.

Definitions set the type

With a definition, its type wins: the value is validated against that type and stored in it, so a request string “5” under an integer definition is stored and read back as the int 5:

use RoundlyConsulting\Attributes\DataTransferObjects\AttributeDefinitionData;
use RoundlyConsulting\Attributes\Enums\AttributeType;
use RoundlyConsulting\Attributes\Facades\Attributes;

Attributes::define(new AttributeDefinitionData('rating', AttributeType::Integer));

Attributes::for($product)->set('rating', $request->input('rating')); // '5' from the request
Attributes::for($product)->get('rating');                            // int(5) — stored in the defined type

The AttributeType enum

The supported types are the cases of RoundlyConsulting\Attributes\Enums\AttributeType. The enum also exposes the inference and conversion it uses internally:

use RoundlyConsulting\Attributes\Enums\AttributeType;

AttributeType::forValue(5);                 // AttributeType::Integer
AttributeType::forValue(now());             // AttributeType::DateTime
AttributeType::forValue('5');               // AttributeType::String_

AttributeType::Boolean->toStorage(true);    // '1'
AttributeType::Array_->toStorage(['a']);    // '["a"]'
AttributeType::Integer->fromStorage('42');  // 42

AttributeType::Float_->toStorage(0.1 + 0.2);                      // '0.30000000000000004' — full precision
AttributeType::DateTime->toStorage('2026-01-01 10:00:00+02:00');  // '2026-01-01T08:00:00+00:00' — UTC
AttributeType::Float_->isNumeric();                               // true — integer and float are one family

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.