---
title: "The Attributes facade — Attributes for Laravel | Roundly"
description: "Attributes::for($owner) for every read and write of one model, plus definitions, validation, pruning and a recording fake."
url: https://roundly-consulting.com/open-source/docs/attributes-for-laravel/facade
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Attributes for Laravel](https://roundly-consulting.com/open-source/docs/attributes-for-laravel.md)

# The Attributes facade

RoundlyConsulting\\Attributes\\Facades\\Attributes is the recommended entry point. Attributes::for($owner) returns the owner’s attribute handle — every read and write in one place:

```php
use RoundlyConsulting\Attributes\Facades\Attributes;

// Writes (validated against definitions, recorded in history, events fired)
Attributes::for($product)->set('color', 'red', meta: ['hex' => '#f00']);     // Attribute
Attributes::for($product)->set('color', 'blue');                              // new value, meta kept
Attributes::for($product)->setMany(['color' => 'red', 'size' => 'L']);        // Collection<Attribute>, keeps others
Attributes::for($product)->sync(['color' => 'red'], forceDelete: false);      // exactly this set
Attributes::for($product)->forget(['color'], forceDelete: false);             // int removed ('color' works too)
Attributes::for($product)->forgetExcept(['color']);                           // list<string> removed
Attributes::for($product)->meta('color', ['hex' => '#ff0000']);               // replace one attribute's meta (null clears)
Attributes::for($product)->stage()->set('color', 'red')->meta('color', ['hex' => '#f00'])->save(); // or ->sync()

// Reads
Attributes::for($product)->all();            // Collection<name, value>
Attributes::for($product)->toKeyValue();     // array<name, value>
Attributes::for($product)->keys();           // list<string>
Attributes::for($product)->get('color');     // value (or the defined default)
Attributes::for($product)->has('color');     // bool
Attributes::for($product)->history('color'); // Collection<AttributeRevision>, newest first

// Housekeeping
Attributes::prune(30);   // force-delete attributes trashed more than 30 days ago (default: config)
```

Writes are validated against definitions, recorded in history when it’s on, and fire events. setMany() and sync() take an optional per-name meta map as their last argument (meta: \['color' => \['hex' => '#f00'\]\]). A value write keeps the attribute’s stored meta unless you pass new meta; meta() replaces it and goes through strict mode, history and the AttributeAttached event like any other write.

Writes are all or nothing: setMany(), sync() and stage()->save() validate every value before the first write and run in one database transaction, so an invalid value or a failing write leaves the owner exactly as it was — nothing detached, nothing half-written.

## The owner handle

Attributes::for($owner) returns an OwnerAttributes handle. Names are always scoped to that owner:

| Method | Returns | What it does |
| --- | --- | --- |
| `set($name, $value = null, $meta = null)` | `Attribute` | Attach or update one attribute; meta is an array or a Collection — without it the stored meta is kept. |
| `setMany(array $attributes, array $meta = [])` | `Collection<int, Attribute>` | Attach or update several, all or nothing; other attributes are kept. |
| `sync(array $attributes, bool $forceDelete = false, array $meta = [])` | `Collection<int, Attribute>` | Make the attributes exactly this set, all or nothing. |
| `forget(array\|string $names, bool $forceDelete = false)` | `int` | Remove attributes; returns how many. |
| `forgetExcept(array $keep, bool $forceDelete = false)` | `list<string>` | Remove every attribute not kept; returns the removed names. |
| `meta($name, $meta)` | `Attribute` | Replace one attribute’s metadata (null clears it) — through strict mode, history and events. |
| `stage()` | `AttributeWriter` | The fluent builder; save() → setMany(), sync() → sync(). |
| `all() / toKeyValue() / keys()` | `Collection / array / list<string>` | Every stored attribute of the owner. |
| `get($name) / has($name)` | `mixed / bool` | One typed value (default applied) / presence. |
| `history(?string $name = null)` | `Collection<int, AttributeRevision>` | Recorded revisions, newest first. |

## Facade methods

The definition and validation methods delegate to the AttributeRegistry singleton — see Definitions & validation:

| Method | Returns | What it does |
| --- | --- | --- |
| `for(Model $owner)` | `OwnerAttributes` | The owner handle — every read and write for one model. |
| `prune(?int $days = null)` | `int` | Force-delete attributes trashed more than $days ago (default: prune\_after\_days). |
| `define($definition) / defineMany(...$definitions)` | `AttributesManager` | Register global definitions (chainable). |
| `has($name) / get($name) / all()` | `bool / ?AttributeDefinitionData / array` | Read the global definitions. |
| `forget($name) / flush()` | `AttributesManager` | Remove one or all global definitions — not stored values. |
| `resolveFor(?$owner, $name) / definitionsFor($owner)` | `definition(s)` | Owner-aware definitions — the model’s schema over the global one. |
| `default($name, ?$owner = null)` | `mixed` | A definition’s declared default. |
| `requiredNames()` | `list<string>` | Names of the required global definitions. |
| `validate($name, $value) / validateFor(?$owner, $name, $value)` | `void` | Throws InvalidAttributeValueException. |
| `assertUnique($owner, $name, $value)` | `void` | Throws DuplicateAttributeValueException. |
| `isStrict() / assertKnown($name, ?$owner = null)` | `bool / void` | Strict mode; assertKnown() throws UnknownAttributeException (the owner’s model schema counts as registered). |
| `fake()` | `AttributesFake` | Facade only — the recording fake (see Testing). |

## Model methods are shorthand

The HasAttributes trait keeps short model methods — attachAttribute(), syncAttributes(), $product->attributes() and the rest — for the same operations. Each delegates to Attributes::for($this), so they behave identically and Attributes::fake() records them. The typed readers (attr(), attributeInt() …) and query scopes live only on the model.

## 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](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## 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.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/attributes-for-laravel.md)
