LARACASTS: Что нового в Laravel 5.1

Сегодня состоялся долгожданный релиз Laravel 5.1
Jeffrey Way уже постарался для нас и сделал целую серию бесплатных скринкастов.
Всем artisan-ам к просмотру обязательно.

Laravel: разные окружения на одном хосте / multi env on one host

Стандартный механизм настройки окружения описан тут. Простой он как двери в милиции, опирается на ответ gethostname() и выглядит вот так
$env = $app->detectEnvironment([
  'env-one-name' => array('hostname1.local'),
  'env-two-name' => array('hostname2')
]);
Все удобно, понятно. Одно "но" заключается в том, что на одном хосте при таких условиях два окружения не потестируешь. Решение я предлагаю такое
$env = $app->detectEnvironment(function(){

  // by path
  if (stristr(__DIR__, 'demo-env-folder-name')) {
    return 'demo';
  }

  // by hostname
  $hostname = gethostname();

  switch ($hostname) {
    case "hostname1.local":
      return 'env-one-name';
    break;

    case "hostname2":
      return 'env-two-name';
    break;

    default:
      return 'production';
    break;
  }
});
Таким образом будем в текущем пути искать название папки для выбранного окружения, то есть для папки /the/path/to/project/demo-env-folder-name будет включено окружение demo, а для других папок будет использоваться определение по хосту, то есть оригинальное. Конечно, есть определенная опасность словить не то окружение после переноса проекта третьими гражданами (которые не в курсе таких поворотов сюжета), но оповещение коллег о таких вещах я считаю должно быть на совести разработчиков. Да и поправить если что легко.

Что нового в Laravel 5?


Как-то я пропустил что Джефри опять забабахал кучу халявных скринкастов.
Тем кто собирается иметь дело с L5 - к просмотру обязательно, очень стоящие скринкасты.

Laravel4: вложенная папка для контроллеров / subfolder for controllers

Натолкнулся на интересный вопрос. Проект большой, контроллеров много становится, захотелось как-то структурировать их чтобы не искать каждый раз. Красноглазие же развивается от этого. Натолкнулся на тему с namespace-ами для групп роутов, да, все работает, но надо изрядно перепиливать все вызовы фасадов, размечать неймспейсы.. короче рутинной возни ненужной куча. Если просто попробовать впилить папку в роут в стиле
Route::post('/lala-page', ['as' => 'lalala', 'uses' => 'subfolder/LalaController@myfinc']);
То оно мало того что выглядит убого так ещё и не работает. А решение было элементарнейшее: перестроить карту классов композером. То есть просто создаем все свои папки где будут жить контроллеры, раскладываем туда контроллеры
app/controllers
app/controllers/my
app/controllers/admin
...
В самих контроллерах ничего не меняем. Просто перестраиваем автозагрузку (из папки проекта разумеется)
composer dump-autoload
И вуаля, все вложенные контроллеры заработали. Мне бы такие инструменты лет 10 назад.. Ну пять хотя-бы :)
REM: см. git diff vendor/composer/autoload_classmap.php

Laravel4: Валидация и кастомные название полей в сообщениях об ошибках

Есть ли у вас такая проблема что.. Нет, правильнее будет сразу скриншот показать.



Маркером отмечены сообщения о том, что валидатору не нравятся данные которые вы пытаетесь сохранить через модель. Все хорошо и здорово кроме названия поля в сообщениях. Смышленый пользователь конечно способен догадаться что за поле имеется ввиду, но очевидно чем больше полей в исходной форме, тем сложнее придется пользователю. Да и как-то.. в общем перфекционисты от этого страдают. Есть "способ вылечить" это (на самом деле документированная возможность). Выглядит это примерно так.
public function isValid()
{
  $validator = Validator::make(
    $this->toArray(),
    [
      'name' => 'required',
      'full_link' => 'required|url|unique:table_links,full_link,' . $this->id,
    ]
  );

  $validator->setAttributeNames([
    'name' => 'Название ссылки',
    'full_link' => 'Ссылка для подсчета кликов',
  ]);

  if ($validator->fails()) {
    $this->errors = $validator->errors();
  }

  return $validator->passes();
}

Теперь сообщения будут выглядеть вот так


Стало куда веселее. Осталось почитать оф. документацию по валидации.
Метод setAttributeNames можно поискать в API, он там есть, но описание скромненькое конечно.
Что касается метода isValid, то это метод модели который используется для валидации вот так
public static function boot()
{
  parent::boot();

  // before update and create
  MyModel::creating(function($item) {
    if (!$item->isValid()) return false;
  });

  MyModel::saving(function ($item) {
    if (!$item->isValid()) return false;
  });
}
То есть на модель вешаются хуки, как видно на события сохранения и создания объекта, которые собственно и вызывают наш метод валидации при соответствующих обстоятельствах.
Пример использования такой модели в контроллере выглядит примерно так
public function itemSave()
{
  $item = MyModel::find(Input::get('id'));
  if (!$item) {
    App::abort(404);
  }

  $item->name = Input::get('name');
  $item->full_link = Input::get('full_link');

  if (!$item->save()) {
    return Redirect::route('item-edit', [$item->id])->withErrors($item->errors);
  }

  return Redirect::route('item-edit', [$item->id])->withItemSaved(1);
}
Пример я упростил, но суть та же. Если сохранение отработало с ошибкой, возвращаемся назад с ошибками из валидатора, иначе всё тип-топ, сообщаем об успешном сохранении. Это всё.

P.S.: Для поддержки языковых версий можно вписывать названия свойств вот так
$validator->setAttributeNames([
  'name' => Lang::get('error.name'),
  'full_link' => Lang::get('error.full_link'),
]);