Aprende a transformar los valores de los atributos de tus modelos Eloquent al obtenerlos y al guardarlos. Se explican de forma práctica cómo definir accesores y mutadores, y cómo usar los casts integrados.
Los accesores, mutadores y casts de atributos son mecanismos que transforman los valores de los atributos de un modelo Eloquent al obtenerlos o al asignarlos desde la instancia.
Accesores: transforman el valor bruto que llega de la BD antes de exponerlo a la aplicación.
Mutadores: transforman el valor asignado por la aplicación antes de guardarlo en la BD.
Casts: permiten declarar la conversión de tipo del atributo sin escribir métodos adicionales.
Para definir un accesor añade al modelo un método protected. El nombre del método se escribe en camelCase y su tipo de retorno debe ser Illuminate\Database\Eloquent\Casts\Attribute.
<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Casts\Attribute;use Illuminate\Database\Eloquent\Model;class User extends Model{ /** * Obtiene el nombre del usuario. */ protected function firstName(): Attribute { return Attribute::make( get: fn (string $value) => ucfirst($value), ); }}
La closure get recibe el valor bruto de la BD. Desde la instancia del modelo puedes acceder al atributo como propiedad first_name.
$user = User::find(1);$firstName = $user->first_name; // Valor con ucfirst() aplicado
Si quieres que el valor calculado por el accesor se incluya en el JSON o el array del modelo, añade el atributo en snake_case a la propiedad $appends del modelo.
Crear un value object a partir de varios atributos
La closure get recibe como segundo argumento $attributes (todos los atributos del modelo). Así puedes combinar varias columnas y devolver un value object.
use App\Support\Address;use Illuminate\Database\Eloquent\Casts\Attribute;protected function address(): Attribute{ return Attribute::make( get: fn (mixed $value, array $attributes) => new Address( $attributes['address_line_one'], $attributes['address_line_two'], ), );}
Los accesores que devuelven un value object devuelven automáticamente la misma instancia gracias a la caché de Eloquent. Para cachear también valores primitivos (cadenas, números) llama a shouldCache().
Un cast es una forma abreviada de declarar la conversión de tipo de un atributo sin necesidad de escribir accesores ni mutadores. Devuélvelos en un array desde el método casts() del modelo.
Puedes tratar de forma transparente columnas JSON/TEXT como arrays PHP.
protected function casts(): array{ return [ 'options' => 'array', ];}
$user = User::find(1);// Se obtiene automáticamente como array PHP$options = $user->options;// Al modificarlo y guardar se serializa a JSON automáticamente$user->options = array_merge($options, ['theme' => 'dark']);$user->save();
Con el operador -> puedes actualizar únicamente una clave concreta del JSON.
El cast array estándar da error si intentas modificar directamente un offset del array. Con AsArrayObject o AsCollection esquivas ese problema.
use Illuminate\Database\Eloquent\Casts\AsArrayObject;use Illuminate\Database\Eloquent\Casts\AsCollection;protected function casts(): array{ return [ 'options' => AsArrayObject::class, // Se trata como ArrayObject 'tags' => AsCollection::class, // Se trata como Collection ];}
Si quieres usar una colección propia, indícalo con using().
use App\Collections\TagCollection;use Illuminate\Database\Eloquent\Casts\AsCollection;protected function casts(): array{ return [ 'tags' => AsCollection::using(TagCollection::class), ];}
Si indicas un formato, se utilizará al serializar a JSON.
protected function casts(): array{ return [ 'published_at' => 'datetime:Y-m-d', ];}
Si quieres cambiar el formato de serialización por defecto de todas las fechas, sobrescribe serializeDate() (no afecta al formato con el que se guardan en BD).
use DateTimeInterface;protected function serializeDate(DateTimeInterface $date): string{ return $date->format('Y-m-d');}
Con immutable_datetime obtienes CarbonImmutable en vez de Carbon. Como no puedes modificar la instancia original, resulta más fácil escribir código sin efectos secundarios al manipular fechas.