29 августа 2016.
Новостная рассылка
Присоединяйтесь к нашему новостному бюллетеню и не пропускайте новости из мира Laravel, анонсы полезных пакетов и советы опытных разработчиков.

Переход с Laravel 5.2 на Laravel 5.3. Руководство по обновлению.

Автор статьи | Официальная документация | Перевел Виталий Николенко

UPD от 29.08.2016

Сессии в конструкторах

Примерные временные затраты: 2-3 Часа

PHP & HHVM

Laravel 5.3 требует PHP 5.6.4 или выше. HHVM официально более не поддерживается, тк не содержит все конструкции языка, имеющиеся в PHP 5.6+.

Устаревшие конструкции

Все что было отмечено deprecataed в Laravel 5.2 было удалено. Необходимо пройтись по этому списку и удостовериться, что вы не используете эти конструкции.

Массивы

Смена порядка ключ/значение

В методах first, last, и contains класса Arr первым параметром в колбеке теперь идет "значение". Например:

Arr::first(function ($value, $key) {
    return ! is_null($value);
});

В предыдущих версиях Laravel, первым параметром передавался ключ ($key) . Но, т.к. в большинстве случаев больше интересует значение, первым параметром теперь передается оно. Вам необходимо сделать "поиск по всему проекту" на наличие использования этих методов и исправить должным образом

Artisan

Команда make:console переименована в make:command.

Аутентификация

Скаффолдинг аутентификации

Два контроллера аутентификации, которые раньше поставлялись вместе с фреймворком были разделены на четыре более мелких контроллера. Эти изменения сделали контроллеры более прозрачными, более простыми для пере-использования. Самый легкий способ обновить приложение – взять новые контроллеры на гитхабе и встроить их в свое приложение.

Также необходимо удостовериться, что вы вызываете метод Route::auth() внутри routes.php . Это метод зарегистрирует роуты к новым аутентификационным контроллерам.

После того, как вы втянули новые контроллеры внутрь приложения, может понадобиться заново реализовать любые нестандартные правки, которые у вас были. Например, если вы использовали нестандартный гард authentication guard, возможно придется переопределить метод guard контроллера . Проверьте каждый из трейтов аутентификации для того, чтобы понять, какие методы необходимо переопределить.

Если вы не вносили правок в аутентификационные контроллеры, простой замены контроллеров + вызов метода Route::auth() внутри routes.php должно быть достаточно.

Уведомления (email) о сбросе пароля

Email-уведомления о сбросе пароля теперь используют новую систему оповещений Laravel. Если вам необходимо внести правки в текст сообщения, необходимо переопределеить метод sendPasswordResetNotification трейта Illuminate\Auth\Passwords\CanResetPassword. Модель User должна использовать новый трейт Illuminate\Notifications\Notifiable для того чтобы пользователи могли получать сообщения о сбросе пароля

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;
}

Не забудьте зарегистрировать Illuminate\Notifications\NotificationServiceProvider в массиве providers внутри конфига config/app.php

POST на Logout

Метод Route::auth теперь регистрирует POST на /logout вместо GET. Эта мера позволяет предотвратить инициацию выхода из системы сторонними веб-приложениями. Для апгрейда либо исправьте свои запросы на выход на POST либо зарегистрируйте новый GET маршрут на урл /logout:

Route::get('/logout', 'Auth\LoginController@logout');

Авторизация

Вызов метода «политики» с именем класса

Некоторые методы «политики» принимают только текущего пользователя, но не экземпляр модели, которую они авторизуют. Ситуация особо часто встречается в случае авторизации операции создания (create) . Например, если вы создаете блог, неплохо бы проверить, а может ли пользователь создавать записи в блоге.

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

/**
 * Определяем, может ли пользователь создавать посты.
 *
 * @param  \App\User  $user
 * @return bool
 */
public function create(User $user)
{
    //
}

Трейт AuthorizesResources

Трейт AuthorizesResources был слит с трейтом AuthorizesRequests. Необходимо удалить использование трейта AuthorizesResources из файла app/Http/Controllers/Controller.php.

Blade

Собственные директивы

В предыдущих версиях Laravel при регистрации собственных директив Blade при помощи метода directive, параметр $expression передаваемый в функцию содержал внешние круглые скобки. В Laravel 5.3 эти внешние скобки не нужны. Ознакомьтесь с секцией Расширение Blade документации и удостоверьтесь, что ваши собственные директивы Blade работают корректно.

Трансляция событий (Broadcasting)

Service Provider

Laravel 5.3 содержит существенные улучшения трансляции событий (event broadcasting). Необходимо добавить новый BroadcastServiceProvider в директорию app/Providers, забрать файл можно на GitHub. Не забудьте добавить его в массив providers конфигурационного файла config/app.php.

Кэш

Расширение кэша через Closure и & $this

При вызове метода Cache::extend с Closure, $this теперь ссылается на инстанс CacheManager, что позволяет вызывать его методы внутри своего Closure:

Cache::extend('memcached', function ($app, $config) {
    try {
        return $this->createMemcachedDriver($config);
    } catch (Exception $e) {
        return $this->createNullDriver($config);
    }
});

Коллекции

Смена порядка ключ/значение

Метода коллекции first, last, и contains теперь передают "значение" в качестве первого параметра в коллбек Closure. Например:

$collection->first(function ($value, $key) {
    return ! is_null($value);
});

В предыдущих версиях Laravel, первым параметром передавался ключ ($key) . Но, т.к. в большинстве случаев больше интересует значение, первым параметром теперь передается оно. Вам необходимо сделать "поиск по всему проекту" на наличие использования этих методов и исправить должным образом

where по умолчанию теперь выполняет "Неточное (Loose)" сравнение

Метод where по умолчанию теперь выполняет "неточное (loose)" сравнение вместо строгого (точного). Если вам необходимо точное сравнение, используйте метод whereStrict.

Метод where также более не принимает третий параметр "точность". Необходимо вызывать либо where либо whereStrict в зависимости от нужд приложения.

Контроллеры

Сессии в конструкторах

В предыдущих версиях Laravel, в конструкторе контроллера можно было получить доступ к данным сессии или инстанс текущего пользователя. Это не было запланированным функционалом фреймворка. В Laravel 5.3, вы не можете получить сессию или аутентифицированного пользователя, тк мидлваре еще не запустились.

В качестве альтернативы, можно определить мидлваре на основе замыкания (Closure) прямо в конструкторе контроллера. Но, прежде че использовать это повдение, удостоверьтесь, что ваше приложение работает на Laravel 5.3.4 или выше:

<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;

class ProjectController extends Controller
{
    /**
     * All of the current user's projects.
     */
    protected $projects;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware(function ($request, $next) {
            $this->projects = Auth::user()->projects;

            return $next($request);
        });
    }
}

Конечно, можно также получить данные сессии и аутентифицированного пользователя путем инжекта Illuminate\Http\Request класса в метод контроллера:

/**
 * Show all of the projects for the current user.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return Response
 */
public function index(Request $request)
{
    $projects = $request->user()->projects;

    $value = $request->session()->get('key');

    //
}

База данных

Коллекции

Построитель запросов(query builder) теперь возвращает коллекции Illuminate\Support\Collection вместо массивов. Это сделано для единообразия возвращаемых результатов билдера и Eloquent.

Если вы не хотите переходить на коллекции, просто добавьте в цепочку вызовов метод all после метода get. Этот метод вернет просто массив PHP с результатами запроса, что позволит поддержать обратную совместимость:

$users = DB::table('users')->get()->all();

Свойство Eloquent $morphClass

Атрибут $morphClass, который можно было определить в модели Eloquent был убран, вместо него рекомендуется использовать «карту превращений» (morph map). Определение карты дает возможность жадной загрузки и предотвращает разного рода ошибки при работе с полиморфическими отношениями. Если ранее вы полагались на свойство $morphClass, необходимо мигрировать на morphMap при помощи следубщей конструкции:

Relation::morphMap([
    'YourCustomMorphName' => YourModel::class,
]);

Например, если ранее у вас был такой атрибут $morphClass:

class User extends Model
{
    protected $morphClass = 'user'
}

Вам необходимо определить следующую morphMap в методе boot своего AppServiceProvider:

use Illuminate\Database\Eloquent\Relation;

Relation::morphMap([
    'user' => User::class,
]);

Метод Eloquent save

Метод save Eloquent теперь возвращает false, если модель не была изменена с момента последней загрузки или сохранения.

Eloquent Scopes

Eloquent scopes теперь учитывают ведущее булево условие. Например, если ваш scope начинается с условия orWhere оно более не будет конвертироваться в нормальное условие where. Если вы полагались на это поведение (например, добавляли orWhere в цикле), необходимо удостовериться, что первым условием идет всегда метод where чтобы избежать логических ошибок.

Если ваши условия наичнаются с метода where никакие дополнительные действия не требуются. Помните, что вы можете всегда проверить получившийся SQL запрос при помощи метода toSql:

User::where('foo', 'bar')->toSql();

Join Clause

Класс JoinClause был переписан с целью унификации синтаксиса с построителем запросов (query builder). Опциональный параметр $where условия on был удален. Для добавления условий "where" необходимо напрямую использовать один из where методов, предлагаемых билдером:

$query->join('table', function($join) {
    $join->on('foo', 'bar')->where('bar', 'baz');
});

Атрибут $bindings также был удален. Для манипуляции биндингами используйте метод addBinding:

$query->join(DB::raw('('.$subquery->toSql().') table'), function($join) use ($subquery) {
    $join->addBinding($subquery->getBindings(), 'join');
});

Шифрование

Mcrypt Encrypter Удален

Mcrypt был объявлен устаревшим в версии Laravel 5.1.0 в июне 2015. Этот шифровальщик был полностью удален в 5.3.0 и заменен более современным решением на базе OpenSSL, которое и является дефолтным во всех версиях, начиная с Laravel 5.1.0.

Если вы до сих пор используете Mcrypt, вам необходимо поменять cipher в файле config/app.php на AES-256-CBC,и установить ключ из 32 байтовой строки, которую можно безопасно сгенерить при помощи команды php artisan key:generate.

Если вы храните у себя в бд, данные зашифрованные при помощи Mcrypt, можете воспользоваться пакетом laravel/legacy-encrypter который релизует поддержку Mcrypt. Советуем только расшифровывать данные этим пакетом, а зашифровывать новым шифровальщиком OpenSSL. Например, вы можете сделать нечто подобное, оформленное в виде консольной команды Artisan:

$legacy = new McryptEncrypter($encryptionKey);

foreach ($records as $record) {
    $record->encrypted = encrypt(
        $legacy->decrypt($record->encrypted)
    );

    $record->save();
}

Обработчик исключений

Конструктор

Базовый обработчик исключений теперь требует в качестве параметра конструктора экземпляр класса Illuminate\Container\Container. Это изменение коснется вас, только, если вы переопределяли метод __construct в файле app/Exception/Handler.php. Если это так, вам надо передать экземпляр контейнера в метод parent::__construct:

parent::__construct(app());

Middleware

Изменение пространства имени can Middleware

Промежуточный слой can представленный в атрибуте $routeMiddleware HTTP ядра теперь ссылается на другой класс, необходимо внести следующие правки:

'can' => \Illuminate\Auth\Middleware\Authorize::class,

can Middleware Authentication Exception

Промежуточный слой can теперь выбрасывает исключение класса Illuminate\Auth\AuthenticationException если пользователь не аутентифицирован. Если вы в ручном режиме перехватывали исключение другого типа, необходимо внести правки в приложение. В большинстве случаев это никак не повлияет на ваше приложение.

Промежуточный слой подстановки модели в маршрутах

Подстановка модели в роутах теперь работает через отдельный промежуточный слой (middleware). Во все приложения необходимо добавить промежуточный слой Illuminate\Routing\Middleware\SubstituteBindings в группу слоев web в файле app/Http/Kernel.php:

\Illuminate\Routing\Middleware\SubstituteBindings::class,

Также необходимо зарегистрировать промежуточный слой подстановки модели в маршрутах в массиве $routeMiddleware ядра HTTP:

'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,

После этого, слой необходимо добавить в группу слоев api:

'api' => [
    'throttle:60,1',
    'bindings',
],

Уведомления

Установка

Laravel 5.3 включает в себя новую систему уведомлений, основанную на драйверах. Вам необходимо зарегистрировать Illuminate\Notifications\NotificationServiceProvider в массиве providers конфигурационного файла config/app.php.

Также необходимо добавить фасад Illuminate\Support\Facades\Notification в массив aliases файла config/app.php.

И наконец, подключаете трейт Illuminate\Notifications\Notifiable к модели User или любой другой модели, которая должна будет уметь получать уведомления.

Постраничная разбивка

Настройка

Подстроить под себя вывод постраничной разбивки в Laravel 5.3 намного проще, по сравнению с предыдущими версиями Laravel 5.x. Вместо создания нового класса "Presenter", вам потребуется всего лишь создать новый шаблон Blade. Самый простой метод видо-изменить постраничный вывод – сделать экспорт шаблонов в папку resources/views/vendor при помощи команды vendor:publish:

php artisan vendor:publish --tag=laravel-pagination

Эта команда поместит шаблоны постраничного вывода в папку resources/views/vendor/pagination. Шаблон default.blade.php отвечает за вывод постраничной навигации по умолчанию. Просто отредактируйте этот файл для изменения навигационного HTML.

Не забудьте изучить документацию по постраничному выводу для более полной информации.

Очереди

Конфигурация

В конфигах очередей все параметры expire должны быть переименованы в retry_after. Также, парметр конфига Beanstalk ttr должен быть переименован в retry_after. Новое имя свойства более ясно отражает его назначение.

Замыкания

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

Сериализация коллекций

Трейт Illuminate\Queue\SerializesModels теперь сериализует должным образом экземпляры класса Illuminate\Database\Eloquent\Collection. Это изменение, скорее всего, не опасно для большинства приложений; однако, если ваше приложение зависит от того факта, что из очереди не приходят коллекции, вам необходимо удостовериться, что это изменение не будет иметь негативного эффекта на приложение.

Обработка очереди в режиме демона

Теперь параметр --daemon не является обязательнфм при запуске Artisan команды queue:work. Запуск php artisan queue:work автоматически подразумевает, что вы хотите запустить обработчик в режиме демона. Если вы хотите обработать одно задание из очереди, необходимо использовать опцию --once:

// Запустить обработчик в режиме демона...
php artisan queue:work

// Обработать одно задание...
php artisan queue:work --once

Изменение в данных событий

Различные типы событий очереди, такие как например JobProcessing и JobProcessed больше не содержат свойство $data. Теперь для получения этих данных необходимо делать вызов $event->job->payload().

Таблица с ошибками очереди (Failed Jobs)

Если в вашем приложении используется таблица failed_jobs, необходимо добавить в нее колонку exception. Колонка exception должна иметь тип TEXT, она будет использоваться для текстового представления исключения, которое привело к ошибке обработки задачи.

Сериаализация моделей при устаревшем создании задач очереди

Обычно задачи в очередь добавляются в Laravel через объект задания, который передается в метод Queue::push. Однако, некоторые приложения могут использовать старый метод для добавления задач в очередь:

Queue::push('ClassName@method');

Если вы добавляете задачи в очередь такми образом, модели Eloquent больше не будут автоматически сериализоваться и извлекаться из очереди должным образом. Если вы хотите, чтобы ваши модели автоматически сериализовались в заданиях очереди - необходимо в классе задачи подключать трейт Illuminate\Queue\SerializesModels и добавлять задания в очередь при помощи нового синтаксиса push:

Queue::push(new ClassName);

Роутинг

Параметры ресурсов по умолчанию в единственном числе

В предыдущих версиях Laravel, параметры роутов ресурсов, зарегистрированных через Route::resource не приводились к единственному числу. Это могло привести к неожиданному поведению при регистрации связки с моделями. Например, рассмотрим следующий зарегистрированный через Route::resource ресурс:

Route::resource('photos', 'PhotoController');

URI для маршрута show будет следующим:

/photos/{photos}

В Laravel 5.3, все параметры маршрутов-ресурсов приводятся к единственному числу. Таким образом, вызов Route::resource зарегистрирует маршрут со следующим URI:

/photos/{photo}

Если вы хотите оставить предыдущее поведение, и не использовать приведение к единственному числу, можно сделать следующий вызов метода singularResourceParameters в файле AppServiceProvider:

use Illuminate\Support\Facades\Route;

Route::singularResourceParameters(false);

На имена маршрутов ресурсов больше не действуют префиксы

Префиксы URL больше не действуют на имена роутов, которые образуются при помощи вызова метода Route::resource, т.к. это поведение фактически перекрывало возможность задать собственные имена маршрутов.

Если ваше приложение использует Route::resource внутри вызова Route::group с опцией prefix, необходимо найти все вызовы функции route и исправить таким образом, чтобы prefix отсутствовал в имени маршрута.

Если это изменение приведет к тому, что у вас появтся несколько одноименных роутов, можете воспользоваться пареметром names при вызове метода Route::resource для того, чтобы задать свое имя указанному маршруту. За подробной информацией обращайтесь к документации.

Валидация

Исключения Form Request

Если валидация не проходит внутри запроса формы (form request), Laravel теперь выбрасывает экземпляр класса Illuminate\Validation\ValidationException вместо HttpException. Если вы в приложении ловите именно инстанс HttpException, выброшенный запросом формы, вам необходимо обновить свой блок catch чтобы отлавливать инстанс ValidationException.

Nullable примитивы

При валидации массивов, булевых, чисел и строк null теперь считается валидным значением, только если правило валидации содержит nullable:

Validate::make($request->all(), [
    'string' => 'nullable|max:5',
]);



Быстрый поиск по JSON документам в Laravel/MySQL при помощи виртуальных полей.

Mohamed Said дает совет, как использовать все возможности MySQL 5 и Laravel для более быстрого поиска по JSON атрибутам.

Представители (Presenters) в Laravel

Шаблон проектирования «Представитель» (Presenter) на практике. И анонс пакета для его реализации