---
title: "Unique, required & defaults — Attributes for Laravel | Roundly"
description: "Enforce unique values per model type or globally, assert required attributes on demand, and read defaults for unset attributes."
url: https://roundly-consulting.com/open-source/docs/attributes-for-laravel/constraints-defaults
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)

# Unique, required & defaults

## Unique values

A unique definition rejects a value that another owner already holds:

```php
use RoundlyConsulting\Attributes\DataTransferObjects\AttributeDefinitionData;
use RoundlyConsulting\Attributes\Enums\AttributeType;
use RoundlyConsulting\Attributes\Enums\UniqueScope;
use RoundlyConsulting\Attributes\Facades\Attributes;

Attributes::define(new AttributeDefinitionData('sku', AttributeType::String_, unique: UniqueScope::Global_));

Attributes::for($a)->set('sku', 'ABC');
Attributes::for($b)->set('sku', 'ABC'); // throws DuplicateAttributeValueException
Attributes::for($a)->set('sku', 'ABC'); // re-saving the owner's own value is fine

Attributes::for($a)->forget('sku');
Attributes::for($b)->set('sku', 'ABC'); // fine — detaching freed the value
```

| Config value | Enum case | Enforces |
| --- | --- | --- |
| none, false, blank or omitted | `UniqueScope::None` | Nothing — the default. |
| owner or true | `UniqueScope::Owner` | Unique among owners of the same model type. |
| global | `UniqueScope::Global_` | Unique across every owner, whatever its type. |

Re-saving the same owner’s own value is idempotent, detaching an attribute — or deleting its owner for good — frees its value, and null values are never checked. DuplicateAttributeValueException exposes attributeName and scope.

Uniqueness is a database guarantee, not just a check before the write: each unique value carries a deterministic hash in the unique\_hash column, which has a unique index — two concurrent writers of the same value cannot both commit, and the loser gets DuplicateAttributeValueException. It works for encrypted values too: their hash is a keyed blind index (an HMAC under a key derived from APP\_KEY), so the database never holds the plaintext. Rotating APP\_KEY changes that key — re-save encrypted unique values afterwards.

## Required attributes

required is enforced on demand, not on every attach — call validateAttributes() when the model should be complete, for example at the end of an import or a checkout step:

```php
use RoundlyConsulting\Attributes\Exceptions\MissingRequiredAttributeException;

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

try {
    $product->validateAttributes();
} catch (MissingRequiredAttributeException $e) {
    $e->attributeName; // 'rating'
}
```

validateAttributes() walks every definition that applies to the model, global and model-declared. It throws MissingRequiredAttributeException for the first required attribute that is absent, and re-validates every present value against its type and rules.

## Default values

A definition’s default is returned by reads when the attribute is not attached. Defaults apply on read only — they are never persisted, and bulk getAttachedAttributes() lists stored rows only:

```php
Attributes::define(new AttributeDefinitionData('retries', AttributeType::Integer, default: 3));

Attributes::for($product)->get('retries'); // 3 when not attached, the stored value when set
$product->attributeInt('retries');         // 3
$product->attr('retries')->int();          // 3

Attributes::for($product)->set('retries', null);
Attributes::for($product)->get('retries'); // null — an explicitly stored null is not replaced
```

An attribute explicitly stored as null reads as null — the default fills in only for an attribute that isn’t attached.

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