Change date format with Accessors and Mutators

Pretty common situation – you have a date field in the MySQL database, which has a default format of YYYY-MM-DD, but the users need to see/edit dates in MM/DD/YYYY. How do you handle it properly in Laravel?

Well, as usual in programming, there are several ways. You can convert it to a proper string in the View files whenever you need, but the best place to handle it is actually Laravel Eloquent Model – with a help of Accessors and Mutators. These words basically mean functions which change the value of the field before saving to DB (mutators) and after extracting it (accessor).

So, for example, we have model Event and a field start_date – we can add two additional functions: getStartDateValue() and setStartDateValue(). Their purpose is opposite to each other, and the syntax is pretty different. Let’s take a look:

class Event extends Eloquent {
	
  private function getStartDateValue() {
    return date('m/d/Y', strtotime($this->attributes['start_date']));
  }

  private function setStartDateValue($value) {
    $date_parts = explode('/', $value);
    $this->attributes['start_date'] = $date_parts[2].'-'.$date_parts[0].'-'.$date_parts[1];
  }

}

Ok, there are several things to explain here. So one by one:

  • Function names consist of three parts: get/set verb, name of the field (note that underscore symbol _ is changed to CamelCase syntax – from start_date to StartDate) and word “Value”
  • Function getStartDateValue() will be triggered every time you take the data from the database, like Event::all() or something – you will recieve event_date column in m/d/Y format and you don’t have to do anything extra in controller/view
  • Function setStartDateValue() will be triggered before saving data to events table – something like Event::create() or $event->save(). Function is expecting your value to be passed as m/d/Y (from datepicker or text field) and then transforms it into a proper YYYY-MM-DD before saving to DB
  • Please note a little different syntax of the functions – they are both working with $this->attributes array, but get function is taking the parameter by its index (so the function itself doesn’t have any parameters), whereas set function has a parameter ($value) which is then transformed and assigned to $this->attributes array element.
  • PHP function strtotime() doesn’t properly work with m/d/Y format, so in the second function we have to treat date as string, split it and recompile in a different format. Of course, there are other ways of doing it – feel free to use your own.
Like our articles?
Check out our Laravel online courses!

7 COMMENTS

  1. You brought some heavy understanding in terms of using accessors and mutators but I need some clarity on my project. I have date of birth values that are from selectors (of course they are different values) and i want them in the same sql column. I am using the implode(); to bring all year, month and date values together before they are saved to the database. Seeing its 3 values and not one i can’t seem to get this to work can you bring some insight into this issue i’m having?

    public function setDobAttribute($dob){

    $dobString = [‘year’, ‘month’, ‘date’];
    $this->attributes[‘_dob’] = implode(‘-‘, array_values($dobString));

    }

    • Hi Rudy,
      From what I see, your issue is the field name. Underscore is needed only if the field is couple of words. If your DB field is called “dob”, then you just put $this->attributes[‘dob’] = …

    • Ok, now I see full picture of the problem – you need to have one field mutator out of three fields. So your $dob should come as the date in the first place – I don’t think it’s possible to have mutator from multiple fields, at least not in this way.

      I would probably make that manipulation in Controller before saving the data. Like:
      $data = $request->all();
      $data[‘_dob’] = $data[‘year’].’-‘.$data[‘month’].’-‘.$data[‘day’];
      $user->update($data);

      Not really pretty or flexible, but should be working.

  2. I find out that in Eloquent has method setAttribute:

    /**
    * Set a given attribute on the model.
    *
    * @param string $key
    * @param mixed $value
    * @return void
    */
    public function setAttribute($key, $value)
    {
    // First we will check for the presence of a mutator for the set operation
    // which simply lets the developers tweak the attribute as it is set on
    // the model, such as “json_encoding” an listing of data for storage.
    if ($this->hasSetMutator($key)) {
    $method = ‘set’.Str::studly($key).’Attribute’;
    return $this->{$method}($value);
    }
    ….

    It is using ‘set’ . $key . ‘Attribute’, but you are describing ‘set’ . $key . ‘Value’ witch does not exists in Eloquent…

LEAVE A REPLY

Please enter your comment!
Please enter your name here