Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

duTchman1990's avatar

Override created_at, updated_at column date format inside map method

In my current project I need created_at, updated_at columns to format with d-m-Y format instead of default MySql format inside collection map method.

$userId  = Auth::user()->id;
                $columns = [
                    'expense_id', 'from_place', 'to_place', 'expense_type', 'vehicle_type', 'expense_date', 'start_km', 'end_km',
                    'nature', 'amount', 'comments', 'created_by', 'created_at', 'status'
                ];

                $EXPENSE_TYPES = config('expense.EXPENSE_TYPES');
                $VEHICLE_TYPES = config('expense.VEHICLE_TYPES');

                $models = Expenses::select($columns)->where('created_by', $userId)
                    ->orderBy('expense_date', 'desc')
                    ->orderBy('expense_id', 'desc')
                    ->whereBetween('expense_date', [$fromDate, $toDate])
                    ->with('user:id,name')
                    ->get()->map(function ($expense) use ($EXPENSE_TYPES, $VEHICLE_TYPES, $columns) {

                    $expense->expense_type = [
                        'id'   => $expense->expense_type,
                        'name' => $EXPENSE_TYPES[$expense->expense_type] ?? ''
                    ];

                    $expense->vehicle_type = [
                        'id'   => $expense->vehicle_type,
                        'name' => $VEHICLE_TYPES[$expense->vehicle_type] ?? 0
                    ];

                    $expense->expense_date  = $expense->expense_date ? strtotime($expense->expense_date) : 0;
                    $expense->created_by    = $expense->user->name ?? '';
                    //$expense->created_at    = Carbon::parse($expense->created_at)->format('h:i');

                    $columns = [
                        'expense_id', 'from_place', 'to_place', 'expense_type', 'vehicle_type', 'expense_date', 'start_km', 'end_km',
                        'nature', 'amount', 'comments', 'created_by', 'created_at'
                    ];

                    return $expense->only($columns);
                });

with this I get created_at value in JSON api like

"created_at": "2021-09-18T07:28:16.000000Z" 

if I use try to format it inside map method like

$expense->created_at    = Carbon::parse($expense->created_at)->format('d-m-Y h:i:s');

I get Data Missing error, but if I change the collection key name to something else like new_date I get proper response from API. My goal is to format it inside map method without changing the column name. Model attribute can do the job, but it does not allow me to change it to any other fomat. That also throws Data Missing error. Simple word I am unable to override created_at inside map, but with foreach I can easily do that without changing the attribute name to something else.

0 likes
1 reply
tykus's avatar

This is a good use case for Eloquent API Resources.

The other option is to specify the format (for JSON representations) in a date cast on the Model class

protected $casts = [
    'created_at' => 'datetime:d-m-Y h:i:s',
];

Otherwise if you prefer your map approach, I would suggest the mutation in the map operation is on an array rather than the model instance; you are running into a problem of Eloquent trying to cast the modified date whenever it is being read again for serialization:

$models = Expenses::select($columns)->where('created_by', $userId)
    ->orderBy('expense_date', 'desc')
    ->orderBy('expense_id', 'desc')
    ->whereBetween('expense_date', [$fromDate, $toDate])
    ->with('user:id,name')
    ->get()
    ->map(function ($expense) use ($EXPENSE_TYPES, $VEHICLE_TYPES, $columns) {
        // ... everything as before *except* mutation of `created_at`
        return array_merge($expense->only($columns), [
            'created_at' => $expense->created_at->format('d-m-Y h:i:s'),
        ]);
    })

Please or to participate in this conversation.