# Eloquent: Mutators
- [Introduction](#introduction)
- [Accessors](#accessors)
- [Mutators](#mutators)
- [Attribute Casting](#attribute-casting)
- [Date Casting](#date-casting)
- [JSON Casting](#json-casting)
## Introduction
Accessors and mutators allow you to transform Eloquent attribute values when you retrieve or set them on model instances. For example, you may want to encrypt a value while it is stored in the database and then automatically decrypt it when you access it on an Eloquent model.
## Accessors
Accessors transform attribute values when you retrieve them. Define typed getter methods in your model:
```dart
class User extends Model {
// Raw attribute access
String? get rawName => getAttribute('name') as String?;
// Accessor with transformation
String get fullName {
final firstName = getAttribute('first_name') as String? ?? '';
final lastName = getAttribute('last_name') as String? ?? '';
return '$firstName $lastName'.trim();
}
// Accessor with formatting
String get formattedPhone {
final phone = getAttribute('phone') as String?;
if (phone == null) return '';
return '+1 (${phone.substring(0, 3)}) ${phone.substring(3, 6)}-${phone.substring(6)}';
}
}
```
### Using Accessors
```dart
final user = await User.find(1);
print(user.fullName); // "John Doe"
print(user.formattedPhone); // "+1 (555) 123-4567"
```
## Mutators
Mutators transform attribute values when you set them. Define setter methods:
```dart
class User extends Model {
// Raw setter
set name(String? value) => setAttribute('name', value);
// Mutator with transformation
set email(String? value) =>
setAttribute('email', value?.toLowerCase().trim());
// Mutator with hashing (example)
set password(String? value) =>
setAttribute('password', value != null ? hashPassword(value) : null);
}
```
### Using Mutators
```dart
final user = User();
user.email = ' JOHN@EXAMPLE.COM ';
print(user.getAttribute('email')); // "john@example.com"
user.password = 'secret123';
// Stored as hashed value
```
## Attribute Casting
The `casts` property provides automatic type conversion for attributes:
```dart
class Task extends Model {
@override
Map get casts => {
'is_completed': 'bool',
'priority': 'int',
'progress': 'double',
'due_date': 'datetime',
'settings': 'json',
};
// Typed accessors use the cast values
bool get isCompleted => getAttribute('is_completed') as bool? ?? false;
int get priority => getAttribute('priority') as int? ?? 0;
double get progress => getAttribute('progress') as double? ?? 0.0;
Carbon? get dueDate => getAttribute('due_date') as Carbon?;
Map? get settings =>
getAttribute('settings') as Map?;
}
```
### Available Cast Types
| Cast | Returns | Database Type |
|------|---------|---------------|
| `bool` | `bool` | INTEGER (0/1) |
| `int` | `int` | INTEGER |
| `double` | `double` | REAL |
| `datetime` | `Carbon` | TEXT (ISO 8601) |
| `json` | `Map` or `List` | TEXT (JSON) |
## Date Casting
Date attributes are automatically converted to Carbon instances:
```dart
class Event extends Model {
@override
Map get casts => {
'starts_at': 'datetime',
'ends_at': 'datetime',
'published_at': 'datetime',
};
Carbon? get startsAt => getAttribute('starts_at') as Carbon?;
Carbon? get endsAt => getAttribute('ends_at') as Carbon?;
Carbon? get publishedAt => getAttribute('published_at') as Carbon?;
// Duration helper
Duration? get duration {
if (startsAt == null || endsAt == null) return null;
return endsAt!.diff(startsAt!);
}
// Check if event is happening now
bool get isHappeningNow {
final now = Carbon.now();
return startsAt?.isBefore(now) == true &&
endsAt?.isAfter(now) == true;
}
}
```
### Working with Dates
```dart
final event = await Event.find(1);
// Format dates
print(event.startsAt?.format('MMMM d, yyyy')); // "January 15, 2024"
// Human readable
print(event.startsAt?.diffForHumans()); // "in 2 days"
// Comparison
if (event.startsAt?.isFuture() == true) {
print('Upcoming event');
}
```
## JSON Casting
JSON attributes are serialized/deserialized automatically:
```dart
class Monitor extends Model {
@override
Map get casts => {
'settings': 'json',
'tags': 'json',
};
// Access as Map
Map get settings =>
(getAttribute('settings') as Map?) ?? {};
// Access as List
List get tags =>
(getAttribute('tags') as List?)?.cast() ?? [];
// Setters
set settings(Map value) =>
setAttribute('settings', value);
set tags(List value) =>
setAttribute('tags', value);
}
```
### Using JSON Attributes
```dart
final monitor = Monitor();
// Set complex data
monitor.settings = {
'timeout': 30,
'retries': 3,
'headers': {'Authorization': 'Bearer token'},
};
monitor.tags = ['production', 'critical', 'api'];
await monitor.save();
// Retrieve
print(monitor.settings['timeout']); // 30
print(monitor.tags.first); // "production"
```
> [!TIP]
> Always define typed getters for your attributes to get IDE autocompletion and type safety throughout your application.