search ESC

Searching…

No results for "".

Type at least 2 characters to search.

Docs

Eloquent: Mutators

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:

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

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:

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

final user = User();

user.email = '  [email protected]  ';
print(user.getAttribute('email')); // "[email protected]"

user.password = 'secret123';
// Stored as hashed value

Attribute Casting

The casts property provides automatic type conversion for attributes:

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:

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

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:

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

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.