Может войдёшь?
Черновики Написать статью Профиль

Основы Laravel 5: Даты, мутаторы и области запросов

перевод Основы Laravel 5 Laracasts

Это перевод видео-урока с Laracasts, серия Laravel 5 Fundamentals, урок №11Dates, Mutators, and Scopes от . Перевод обновлён . Опечатка? Выдели и нажми Ctrl+Enter.

(0:00)
Итак, мы хотим разобраться с валидацией, но для начала, давайте чуть-чуть поговорим о паре других моментов, чтобы наш код стал чище. Посмотрим на несколько хороших примеров, чтобы немного больше поработать с Carbon. Мы можем поговорить об областях запросов (query scopes) и ещё о ряде мелких моментов типа этого. OK, назад к PHPArticlesController, где мы остановились в прошлый раз. И мы можем на самом деле улучшить этот код. Сейчас мы просто настроили поле PHPpublished_at на текущее время. И это просто потому, что мы не хотели разбираться с датами.

(0:30)
Однако в жизни всё конечно не так. Так почему бы нам не исправить это? А в процессе вы увидите некоторые классные штуки, связанные с Eloquent. ОК, так что я тут всё полностью удалю и вставлю напрямую в виде параметра. Намного лучше, не так ли? Далее, нам нужно перейти в наше представление, потому что если помните, (если мы перейдём обратно в браузер), у нас тут в форме нет поля PHPpublished_at. В действительности, вы вероятно будете использовать какой-то специальный JavaScript календарь, так?

(1:00)
Но в нашем случае, давайте используем простой ввод даты с помощью HTML5. Итак, давайте сделаем это. Мы создадим текстовое поле и назовём его PHPpublished_at. Но мы изменим тут текст на «Дата публикации» (Publish On):

PHP
{!! Form::label('published_at''Publish On:') !!}

И далее, тут должно быть не текстовое поле, а дата, но я не думаю, что в Laravel есть тип date. Вместо этого мы используем обычный метод ввода. И таким образом я могу указать тип входных данных, в этом случае — date:

PHP
{!! Form::input('date''published_at'null, ['class' => 'form-control']) !!}

(1:30)
OK, давайте просто оставим это как есть и взглянем что мы получили в браузере. Запустим, и готово. И к счастью, поскольку мы используем современный браузер, он принудительно потребует от нас нужный формат. OK, далее, я думаю было бы хорошо ставить по умолчанию сегодняшний день. Таким образом, мне не нужно будет постоянно вводить дату вручную. Это надоедает. Так что давайте сделаем это. Я переключусь обратно. И вот здесь, третий аргумент — это то, что всегда будет по умолчанию. Но помните что тут нельзя просто ввести что-угодно. Вводимые данные должны быть в правильном формате. Поэтому здесь должна быть дата.

(2:00)
Таким образом мы переключаемся обратно и да, если вы хотите можно использовать Carbon. Например вот так:

PHP
format('Y-m-d')

Но в данном случае, нам действительно это не требуется. Мы можем просто использовать простую функцию PHP: PHPdate('Y-m-d'). Вот так.
ОК, давайте переключимся обратно, обновим страницу, и теперь у нас есть значение по умолчанию, которое вы можете настроить, когда вам нужно. Прекрасно. А теперь давайте попробуем кое-что ещё. Давайте просто впишем тут белиберду, в тело — белиберду и дата публикации будет 30 января.

(2:30)
Так что если я это запущу, то, да, кажется, что всё сработало, но давайте посмотрим внимательно.

shsqlite3 storage/database.sqlite

И там:

sqlselect * from articles;

И вот смотрите. Да, дата была установлена на 30 января, но было бы неплохо, если бы мы на самом деле здесь также сохранили и текущее время. Таким образом, внутри в БД, мы могли бы знать, что эта статья была опубликована 30 января в 4:23. Так? На данный момент мы этого не знаем.

(3:00)
Так почему бы нам это не исправить? И по ходу я покажу вам некоторые классные вещи. Сейчас я переключусь к моей модели PHPArticle в Eloquent, чтобы вы познакомились с методами доступа и модифицирующими методами (мутаторами). Они дают нам возможность манипулировать данными перед добавлением в БД или после их извлечения из неё. Так например, с помощью мутатора, я мог бы допустим создать метод с названием PHPsetPublishedAtAttribute.
Обратите внимание на принятое соглашение, это очень важно:

PHP
public function setPublishedAtAttribute($date)

(3:30)
У нас есть слово set, за ним название поля, так что если бы мы пытались манипулировать со столбцом name, то мы бы написали:

PHP
setNameAttribute

Вот такое здесь соглашение. Так, например, если мы хотим задать адрес:

PHP
setAddressAttribute

И обратите внимание, в случаях, где у вас есть подчеркивания, вы просто можете использовать стиль CamelCase. ОК, так что теперь, когда вы устанавливаете атрибут PHPpublished_at, я хочу убедиться что он в правильном формате. Поэтому мы можем задать атрибуты напрямую:

PHP
$this->attributes['published_at'] = Carbon::createFromFormat('Y-m-d'$date);

(4:00)
Почему бы нам не использовать здесь Carbon? Так что мы импортируем его. И передадим строку PHP$date в качестве второго аргумента.
Вот и всё. Итак, мы корректно разбили строку, и время также будет добавлено если это имеет смысл для вашего проекта. Хорошо, давайте попробуем ещё раз. Мы создадим новую статью, ещё немного белиберды тут, и опубликуем 28 января.

(4:30)
ОК, так что теперь, если мы снова сделаем select *, то вы увидите, что мы установили и время тоже. Однако вот кое-что интересное. Если мы установим дату в будущем, то вы просто можете решить, допустим, что 28 января в полночь, статья будет опубликована. И если это ваш случай, то мы вряд ли захотим так делать. Вместо этого вы могли бы написать что-то вроде:

PHP
Carbon::parse($date)

чтобы попытаться разобраться с датой. Теперь если вернёмся назад.

(5:00)
Третья попытка. И мы снова запустим. Посмотрите на разницу. Сейчас мы запустили и дата будет установлена на 28 января, но у нас здесь нет времени, так что по сути она настроена на полночь. Итак, это начинает хорошо выглядеть. Однако сейчас у нас появилась проблема. Если я обновлю страницу, я вижу статьи, которые будут опубликованы в будущем. Например любые из вот этих, мы не должны их здесь отображать, потому что все они настроены на публикацию в течение следующих пары дней.

(5:30)
Поэтому мы должны убедиться, что у нас есть некая область действия запроса (query scope), чтобы ограничить вывод. Вот как мы это делаем. Сначала я покажу вам непосредственно в контроллере, а затем мы немного подчистим тут всё, перейдя к модели Eloquent. Так что прямо здесь наверху, мы говорим:

PHP
$articles Article::latest('published_at') ->get();

(упорядочим их все по убыванию по PHPpublished_at, и затем сделаем PHPget() на весь набор)
На самом деле мы не хотим этого. В действительности мы хотим ограничить их:

PHP
->where ('published_at' '<=' Carbon::now())->get();

(6:00)
OK, так что теперь, если мы переключимся обратно, и мы обновим страницу, обратите внимание, что теперь мы их не отображаем, поскольку мы скорректировали запрос. Получить все статьи, упорядочить их по PHPpublished_at в убывающем порядке, но только получить статьи где в этом столбце, их время меньше или равно настоящему моменту. Поэтому всё, что находится в будущем, т.е. больше чем сейчас, конечно же будет исключено. И тогда мы получим результаты этого запроса.

(6:30)
Но теперь вы можете видеть, что это начинает выглядеть несколько путано, особенно когда вы можете представить себе ситуации использования подобных запросов в нескольких частях приложения. Досадно, что мы должны писать такие довольно-таки длинные строки кода для чего-то, что является своего рода неотъемлемой частью для нашего приложения. И вот здесь-то области запросов (или «границы выборки» — scope) и могут очень пригодиться. Мы можем взять запрос и добавить к нему условие непосредственно в модели Eloquent. Или другими словами, какой бы здесь был хороший способ, чтобы изобразить это? Мы хотим последние статьи, но я также хочу те, которые были опубликованы.

(7:00)
Это имеет смысл, правда? Так что, возможно, я мог бы написать здесь, PHPpublished() и теперь это выглядит почище, не так ли? ОК, давайте сделаем это. Я хочу область под названием PHPpublished(). Так что перейдем к нашей модели и добавим новую область запроса прямо здесь. Соглашение для этого случая — слово scope и за ним имя. Мы назвали наш PHPpublished() и он будет принимать наш конструктор запросов:

PHP
public function scopePublished($query)

Теперь мы можем просто вставить то что у нас там было раньше, так:

PHP
$query->where('published_at''<='Carbon::now());

(7:30)
Итак, вы добавили свою первую область. Если мы вернёмся и обновим, всё должно по-прежнему работать, и точно, всё работает. Но теперь, преимущество в том, что вы можете использовать это в любом месте в вашем приложении. Или что делать, если вы хотите сделать обратное — выбрать все остальные статьи? Допустим вам необходим некий способ в вашем приложении, чтобы получить все статьи, которые ещё только будут опубликованы. Это могло бы быть полезно для панели администратора, не так ли? Давайте напишем:

PHP
scopeUnpublished($query)

(8:00)
И единственное отличие будет в том, чтобы получить статьи, где дата PHPpublished_at будет в будущем (т.е. больше чем сейчас):

PHP
$query->where('published_at''>'Carbon::now());

ОК, давайте это проверим. Теперь мы хотим выбрать только неопубликованные статьи. Итак, если мы обновим, всё работает. Проще простого. ОК, мы почти закончили этот урок. Я лишь хочу вам тут показать еще одну штуку. Представьте, что когда мы смотрим статью, нам нужно что-то сделать с датой в некоторых случаях.

(8:30)
Так что давайте сделаем так:

PHP
dd($article->published_at);

И посмотрим как это выглядит. OK, обновим страницу. Давайте-ка взглянем. И да, у нас тут временной штамп (timestamp) в виде строки: 2015-01-23 21:21:10. Но было бы неплохо, если бы это был экземпляр Carbon. Потому что вот кое-что прикольное. Взгляните на поле created_at. Это специальное поле, о которых Laravel уже знает. И обратите внимание, что он достаточно умён, чтобы сконвертировать его в экземпляры Carbon.

(9:00)
Опять же, если Carbon для вас — нечто абсолютно новое, у нас есть посвящённое ему видео на Laracasts.com, и там вы можете узнать о нем всё более подробно. Но я покажу вам пару вещей, которые вы можете с ним сделать. Вы можете делать некоторые простые вещи, так например, у нас есть хорошие методы доступа к свойствам. Так что если я хочу выбрать год, то это очень легко. Просто напишите PHP->year:

PHP
dd($article->created_at->year);

месяц:

PHP
dd($article->created_at->month);

Вернёмся, обновим. Или мы даже можем манипулировать свойствами очень простым и читаемым образом. Например, если я хочу добавить 8 дней к дате:

PHP
dd($article->created_at->addDays(8));

OK. Теперь если мы обновим страницу, мы изменили дату на 8 дней с момента PHPpublished_at.

(9:30)
Или вы могли бы даже задать новый формат. Например, вы можете сказать:

PHP
dd($article->created_at->addDays(8)->format('Y-m'));

Давайте посмотрим. Обновите и теперь это работает. Или мы могли бы даже отформатировать дату в более читаемый вид с помощью метода PHPdiffForHumans(). И это действительно полезно, например для лент новостей. Представьте себе Twitter, где у вас есть статус, а ниже говорится: «Этот статус был опубликован 12 минут назад». Вы могли бы использовать что-то подобное, используя стандартный способ:

PHP
dd($article->created_at->addDays(8)->diffForHumans());

(10:00)
Обновим, и похоже что мы опубликуем эту статью через 5 дней. Так что, как вы можете себе представить, это очень удобно, если дата и время могут быть автоматически преобразованы в экземпляры Carbon. Но давайте вернёмся тут к PHPpublished_at и кстати, всё то же самое было бы верно и для PHPupdated_at. Но в любом случае, давайте напишем снова PHPpublished_at:

PHP
dd($article->published_at);

Как видите, ничего из этого мы использовать не можем, так как у нас просто строка. Поэтому было бы здорово, если бы мы могли сказать Laravel:

(10:30)
«У меня тут был дополнительный временной штамп, и я хочу чтобы ты работал с ним как с экземпляром Carbon». Вот как мы это делаем. Мы вернёмся к статье, и добавим такое свойство:

PHP
protected $dates = ['published_at'];

Здесь я задам имя столбца. И вот и всё. Так что теперь если мы вернёмся и обновим, мы видим, что это экземпляр Carbon. Что означает, что у нас есть доступ ко всем этим методам и методам PHPget(), как мы и делали со столбцами PHPcreated_at, PHPupdated_at и PHPdeleted_at.

(11:00)
И если вам интересно, как это работает, то вы всегда можете покопаться с моделями. Теперь, если мы посмотрим на метод PHPgetDates() вот здесь, вы увидите, что он принимает наши значения по умолчанию, поэтому он по-прежнему будет обрабатывать PHPcreated_at и PHPupdated как временные штампы. Но он объединит (merge) те значения по умолчанию с тем, что мы установили в качестве свойства PHP->dates. Так что вот как здесь это делается.
Хорошо, мы делаем большие успехи, не так ли?
В этом уроке вы узнали немного больше о Carbon, вы узнали об областях запросов, вы познакомились с модифицирующими методами-мутаторами.

(11:30)
Мы также научились принимать временные штампы любого типа и работать с ними как с экземплярами Carbon, и если мы переключимся обратно в PHPArticlesController, мы основательно почистили наш контроллер. Итак, в нашем следующем видео, мы уже достаточно долго ждали, и нам действительно нужно разобраться с валидацией. Там и увидимся!

Как вы считаете, полезен ли этот материал? Да Нет

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.