Настройка формата дат

Настройка формата дат в проекте Ларавел

Представьте, что на вашем сайте есть поле с выбором даты. И, после того, как вы полностью сделали проект, клиент приходит с поправочкой: «Кстати, формат даты должен быть в формате m/d/y» . Придется повозится со всеми формами…

Как предотвратить это в самом начале проекта? Как сделать формат дат легко настраиваемым? И в базы данных, и в полях выбора даты и во всех шаблонах?

Самая большая проблема в том, что формат дат обрабатывается в трех местах:

  • Поля Базы данных должны быть всегда в формате YYYY-MM-DD;
  • Бэкенд Laravel: в формах/шаблонах должен быть любой формат, какой захочет клиент, но при сохранении в базу данных он должен быть преобразован в YYYY-MM-DD;
  • JavaScript datepicker: форматы дат в JS не совпадают с форматами PHP, мы увидим это в примере ниже.

Итак, как всё это синхронизировать? Сначала давайте заставим всё это работать, а позже сделаем настраиваемыми.

JavaScript Datepicker Формат

В этом примере мы будем использовать Bootstrap Datepicker

Чтобы это заработало, нам нужны следующий код:

<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css" rel="stylesheet" />

...

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>

<script>
$(document).ready(function () {
  $('.date').datetimepicker({
    format: 'MM/DD/YYYY',
    locale: 'en'
  });
</script>

Как видите, мы передаем формат MM/DD/YYYY, который в PHP станет m/d/Y. Говорил о разнице форматов в JavaScript и PHP?

Результат:

ДатаПикер

Сохранение даты в базе данных

Если мы отправим эти данные в какой-либо контроллер, то получим дату в точности такой, как она поступает из DatePicker. И если мы попытаемся сохранить его сразу в базу данных как m/d/Y, то получим ошибку SQL.

Поэтому нам нужно преобразовать её в правильный формат. Есть несколько мест, где мы можем это сделать.

Вариант 1. TransactionController метод store():

public function store(Request $request)
{
    $data = $request->all();
    $data['transaction_date'] = Carbon::createFromFormat('m/d/Y', $request->transaction_date)->format('Y-m-d');
    $transaction = Transaction::create($data);
}

Проблема с этим вариантом в том, что вам придется делать то же самое в методе update(), и везде, где вам нужно хранить эти данные. но есть более гибкий вариант.

Вариант 2. Преобразователь модели (Mutator) app/Transaction.php:

public function setTransactionDateAttribute($value)
{
    $this->attributes['transaction_date'] = Carbon::createFromFormat('m/d/Y', $value)->format('Y-m-d');
}

Отображение даты в формах/шаблонах

Хорошо, мы сохранили дату в формате Y-m-d в базе данных. Но для пользователей должен отображаться формат m/d/Y. Итак, аналогично приведенному выше примеру, нам нужно создать читателя модели (accessor).

app/Transaction.php:

public function getTransactionDateAttribute($value)
{
    return Carbon::parse($value)->format('m/d/Y');
}

Подробнее о преобразователях и читателях в официальной документации.

Сделайте это настраиваемым

Для всех приведенных выше примеров нам нужно заменить точные форматы значениями из конфига.

Давайте добавим эти переменные в config/app.php:

return [
  'date_format' => 'm/d/Y',
  'date_format_javascript' => 'MM/DD/YYYY',
];

Затем, мы можем это использовать в Laravel:

Carbon::createFromFormat(config('app.date_format'), $value)->format('Y-m-d');
Carbon::parse($value)->format(config('app.date_format'));

Мы не можем вставить переменную напрямую в JavaScript, но мы можем добавить эту команду в шаблон:

$('.date').datetimepicker({
  format: '{{ config('app.date_format_javascript') }}',
  locale: 'en'
});

Теперь, если нам нужно изменить формат дат во всем проекте, то всё, что нам нужно сделать, это изменить переменные в файле config/app.php.

Автор: Povilas Korop
Перевод: Demiurge Ash