Представьте, что на вашем сайте есть поле с выбором даты. И, после того, как вы полностью сделали проект, клиент приходит с поправочкой: «Кстати, формат даты должен быть в формате 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
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.