{{TOC}} {{DOCVER 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15, 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01}} .(tl_note) Данная статья документации актуальна только для версий 5.2 и 5.1 и была удалена в версии 5.3. == Введение == Это руководство позволит вам быстро освоить фреймворк Laravel. Оно содержит информацию о миграциях баз данных, Eloquent ORM, маршрутизации, аутентификации, авторизации, валидации, представлениях и Blade-шаблонах. Это отличная отправная точка для новичков в фреймворке Laravel и PHP-фреймворках в целом. Если вы уже использовали Laravel или другие PHP-фреймворки, вы можете ознакомиться с нашими более продвинутыми руководствами. Чтобы рассмотреть основной набор функций Laravel, мы создадим простой список задач и будем придерживаться его (типичный пример списка "to-do"). В отличие от базового данное руководство позволит пользователям создавать аккаунты и аутентифицироваться в приложении. Полный финальный вариант исходного кода для этого проекта ((http://github.com/laravel/quickstart-intermediate доступен на GitHub)). == Установка == **Установка Laravel** Конечно, в первую очередь вам будет нужен свежий фреймворк Laravel. Чтобы запустить его, вы можете использовать ((/docs/v5/homestead виртуальную машину Homestead)) или локальную PHP-среду на ваш выбор. Как только ваше окружение будет готово, вы можете установить фреймворк Laravel, используя Composer: %%(sh) composer create-project laravel/laravel quickstart --prefer-dist %% **Установка проекта Quickstart (не обязательно)** Вы можете просто прочитать данное руководство. Однако, если вы хотите загрузить исходный код для этого руководства и выполнить его на локальной машине, то можете клонировать Git хранилище и установить зависимости: %%(sh) git clone https://github.com/laravel/quickstart-intermediate quickstart cd quickstart composer install php artisan migrate %% Более полную информацию о создании локальной среды разработки Laravel вы сможете найти в документации по ((/docs/v5/homestead Homestead)) и по ((/docs/v5/installation установке)). == Подготовка базы данных == === Миграции БД === Во-первых, давайте используем миграцию для определения таблицы базы данных для хранения всех наших задач. Миграции БД в Laravel позволяют простым способом определить структуру таблицы базы данных и выполнять модификации с использованием простого и выразительного PHP кода. Вместо того чтобы вручную добавлять столбцы в свои локальные копии БД, ваши товарищи по команде могут просто запустить миграции, которые вы поместили в систему управления версиями. ==== Таблица %%(t)users%% ==== Поскольку мы решили, что пользователь может создать свой аккаунт в приложении, нам нужна таблица для хранениях пользователей. К счастью, Laravel уже поставляется с миграцией, включающей в себя базовую таблицу %%(t)users%%. Поэтому нам не нужно вручную её создавать. По умолчанию миграция для таблицы %%(t)users%% находится в каталоге %%(t)database/migrations%%. ==== Таблица %%(t)tasks%% ==== Теперь давайте создадим таблицу, которая будет содержать все наши задачи. Для создания различных классов может быть использован ((/docs/v5/artisan интерфейс Artisan)). Он избавит вас от ручной генерации кода при создании проектов Laravel. Поэтому давайте используем команду %%(sh)make:migration%% для создания миграции новой базы данных для нашей таблицы %%(t)tasks%%: %%(sh) php artisan make:migration create_tasks_table --create=tasks %% Миграция будет помещена в каталог %%(t)database/migrations%% вашего проекта. Как вы могли заметить, команда %%(sh)make:migration%% уже добавила автоинкрементный ID и метки времени к файлу миграции. Давайте отредактируем этот файл и добавим дополнительный столбец %%(t)name%% для имён наших задач, а также столбец %%(t)user_id%%, который свяжет таблицу %%(t)tasks%% с таблицей %%(t)users%%: %% increments('id'); $table->integer('user_id')->unsigned()->index(); $table->string('name'); $table->timestamps(); }); } /** * Откатить миграции * * @return void */ public function down() { Schema::drop('tasks'); } } %% Чтобы запустить нашу миграцию, мы будем использовать команду Artisan %%(sh)migrate%%. Если вы используете Homestead, вы должны выполнить эту команду на своей виртуальной машине, так как у вашей host-машины не будет прямого доступа к базе данных: %%(sh) php artisan migrate %% Эта команда создаст все наши таблицы БД. Если вы просмотрите таблицы, используя какой-либо клиент для БД, вы должны заметить новую таблицу %%(t)tasks%%, которая содержит столбцы, определённые в нашей миграции. Теперь мы готовы определить модели Eloquent ORM для наших задач! === Модели Eloquent === ((/docs/v5/eloquent Eloquent)) - это стандартное ORM для Laravel (объектно-реляционное отображение). Eloquent делает безболезненным получение и хранение данных в вашей базе данных, используя чётко определённые "модели". Обычно, каждая Eloquent модель однозначно соответствует одной таблице базы данных. ==== Модель %%(t)User%% ==== В первую очередь нам нужна модель, соответствующая нашей таблице %%(t)users%%. Однако, если вы зайдете в папку %%(t)app%% вашего проекта, вы увидите, что Laravel уже поставляется в комплекте с моделью %%(t)User%%, поэтому нам не нужно создавать её вручную. ==== Модель %%(t)Task%% ==== Давайте определим модель %%(t)Task%%, которая будет соответствовать только что созданной нами таблице %%(t)tasks%%. Мы снова можем использовать команду Artisan, чтобы сгенерировать эту модель. В этом случае мы будем использовать команду %%(sh)make:model%%: %%(sh) php artisan make:model Task %% Модель будет помещена в каталог %%(t)app%% вашего приложения. По умолчанию класс модели пуст. Нам не надо явно указывать, какой таблице соответствует Eloquent модель, потому что подразумевается, что имя таблицы – это имя модели во множественном числе (s на конце). В этом случае предполагается, что модель %%(t)Task%% соответствует таблице базы данных %%(t)tasks%%. Давайте добавим несколько вещей в эту модель. Для начала определим, что атрибут %%(t)name%% этой модели должен быть массово присваиваемым. Это позволит нам заполнить атрибут %%(t)name%% при использовании метода Eloquent %%create()%%: %% tasks as $task) { echo $task->name; } %% ==== Отношение %%(t)tasks%% ==== Во-первых, давайте определим отношение %%(tasks)%% для нашей модели %%(t)User%%. Отношения Eloquent определены как методы моделей. Eloquent поддерживает несколько различных типов отношений, с которыми можно ознакомиться в ((/docs/v5/eloquent-relationships полной документации по Eloquent)). Мы определим функцию %%tasks%% в модели %%(t)User%%, которая вызывает Eloquent-метод %%hasMany()%%: %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) ~%% hasMany(Task::class); } } ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) ~%% hasMany(Task::class); } } ~%% %% ==== Отношение %%(t)user%% ==== Теперь давайте определим отношение %%(t)user%% для модели %%(t)Tasks%%. И снова мы определим отношение как метод модели. В этом случае мы будем использовать Eloquent-метод %%belongsTo()%%, определяющий отношение: %% belongsTo(User::class); } } %% Прекрасно! Теперь наши отношения определены, и мы можем начать создавать наши контроллеры! == Маршрутизация == В ((/docs/v5/quickstart базовой версии)) нашего приложения мы определили всю нашу логику в файле %%(t)routes.php%%, используя замыкания. В данном приложении мы будем использовать ((/docs/v5/controllers контроллеры)) для организации наших маршрутов. Контроллеры позволят нам лучше организовать логику HTTP-запросов в нескольких файлах. === Вывод представления === У нас будет один маршрут, использующий замыкание: наш маршрут %%(t)/%%, представляющий из себя лендинг для гостей приложения. Давайте заполним наш маршрут %%(t)/%%. По этому маршруту мы хотим отрисовывать HTML-шаблон, который содержит страницу "welcome". В Laravel все HTML-шаблоны хранятся в каталоге %%(t)resources/views%%, и мы можем использовать вспомогательную функцию %%view()%%, чтобы возвратить один из этих шаблонов по нашему маршруту: %% Route::get('/', function () { return view('welcome'); }); %% Конечно, нам необходимо создать это представление, давайте сделаем это! === Аутентификация === Помните, что мы также должны позволить пользователям создавать учётные записи и входить в наше приложение. Как правило, построение всего слоя аутентификации в веб-приложении является трудоёмкой задачей . Однако, так как это распространённая задача, Laravel попытался сделать эту процедуру абсолютно безболезненной. Во-первых, обратите внимание, что %%(t)app/Http/Controllers/Auth/AuthController%% уже включён в приложение Laravel. Этот контроллер использует специальный типаж (trait) %%(t)AuthenticatesAndRegistersUsers%% со всей необходимой логикой для создания и аутентификации пользователей. ==== Маршруты и представления аутентификации ==== Итак, что нам осталось сделать? Нам всё ещё нужно создать шаблоны регистрации и входа в систему, а также определить маршруты, указывающие на контроллер аутентификации. %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Мы можем сделать это с помощью Artisan-команды %%(sh)make:auth%%: %%(sh) php artisan make:auth ~%% Теперь нам осталось только добавить маршруты аутентификации в наш файл маршрутов. Это можно сделать методом %%auth()%% фасада %%(t)Route%%, который зарегистрирует все необходимые нам маршруты для регистрации, входа и сброса пароля: ~%% // Маршруты аутентификации... Route::auth(); ~%% Когда маршруты %%(t)auth%% зарегистрированы, проверьте, что свойство %%$redirectTo%% контроллера %%(t)app/Http/Controllers/Auth/AuthController%% имеет значение %%/tasks%%: ~%% protected $redirectTo = '/tasks'; ~%% А также необходимо изменить в файле %%(t)app/Http/Middleware/RedirectIfAuthenticated.php%% путь переадресации: ~%% return redirect('/tasks'); ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) Для начала давайте добавим нужные нам маршруты в файл %%(t)app/Http/routes.php%%: ~%% // Маршруты аутентификации... Route::get('auth/login', 'Auth\AuthController@getLogin'); Route::post('auth/login', 'Auth\AuthController@postLogin'); Route::get('auth/logout', 'Auth\AuthController@getLogout'); // Маршруты регистрации... Route::get('auth/register', 'Auth\AuthController@getRegister'); Route::post('auth/register', 'Auth\AuthController@postRegister'); ~%% ==== Представления аутентификации ==== Для аутентификации необходимо создать %%(t)login.blade.php%% и %%(t)register.blade.php%% в папке %%(t)resources/views/auth%%. Конечно, дизайн и стиль этих представлений не имеет значения. Тем не менее, они должны содержать по крайней мере несколько основных полей. Файл %%(t)register.blade.php%% должен содержать форму, включающую в себя поля %%(t)name%%, %%(t)email%%, %%(t)password%% и %%(t)password_confirmation%%, эта форма должна создавать %%(t)POST%% запрос к маршруту %%(t)/auth/register%%. Файл %%(t)login.blade.php%% должен содержать форму, включающую в себя поля %%(t)email%% и %%(t)password%%, эта форма должна создавать %%(t)POST%% запрос к маршруту %%(t)/auth/login%%. %% .(alert) Если вы хотите просмотреть полные примеры для этих представлений, помните, что весь исходный код приложения ((https://github.com/laravel/quickstart-intermediate доступен на GitHub)). === Контроллер задач === Поскольку мы знаем, что нам нужно получать и сохранять задачи, давайте создадим %%(t)TaskController%% с помощью командной строки Artisan, при этом новый контроллер будет помещён в папку %%(t)app/Http/Controllers%%: %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) %%(sh) php artisan make:controller TaskController ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) %%(sh) php artisan make:controller TaskController --plain ~%% %% Теперь, когда контроллер создан, давайте создадим стабы для некоторых маршрутов в нашем файле %%(t)app/Http/routes.php%%, указывающих на контроллер: %% Route::get('/tasks', 'TaskController@index'); Route::post('/task', 'TaskController@store'); Route::delete('/task/{task}', 'TaskController@destroy'); %% ==== Аутентификация всех маршрутов задач ==== В данном приложении мы хотим, чтобы все наши маршруты задач требовали аутентификации пользователя. Другими словами, пользователь должен зайти в систему, чтобы создать задачу. Поэтому мы должны ограничить доступ к нашим маршрутам задач и открывать доступ только аутентифицированным пользователям. Laravel контролирует это, используя ((/docs/v5/middleware посредника)). Чтобы проверять аутентификацию пользователя в каждом действии, мы можем добавить вызов метода %%(t)middleware%% в конструктор контроллера. Все доступные посредники маршрута определены в файле %%(t)app/Http/Kernel.php%%. В данном случае мы хотим добавить посредник %%(t)auth%% ко всем методам контроллера: %% middleware('auth'); } } %% == Создание макетов и представлений == Основная часть этого приложения содержит одно представление с формой добавления новых задач, а также список всех текущих задач. Чтобы помочь вам визуализировать представление, мы сделали скриншот законченного приложения со стандартными стилями Bootstrap CSS: {{Image /packages/proger/habravel/uploads/374-basic-overview.png}} === Определяем макет === Почти все веб-приложения используют один макет на всех своих страницах. Например, у нашего приложения есть верхняя панель навигации, которая присутствовала бы на каждой странице (если бы у нас их было больше одной). Laravel упрощает использование этих общих функций на всех страницах, используя **макеты** Blade. Как мы выяснили ранее, все представления Laravel хранятся в %%(t)resources/views%%. Давайте определим представление нового макета в %%(t)resources/views/layouts/app.blade.php%%. Расширение %%(t).blade.php%% даёт фреймворку команду использовать ((/docs/v5/blade механизм шаблонной обработки Blade)), чтобы отрисовать это представление. Конечно, в Laravel вы можете использовать и простые PHP-шаблоны. Однако Blade позволяет быстро написать простой и небольшой шаблон. Наше представление %%(t)app.blade.php%% должно выглядеть примерно так: %%(html) Laravel Quickstart - Intermediate
@yield('content') %% Обратите внимание на строчку %%(html)@yield('content')%% в макете. Это специальная Blade-директива для указания всем дочерним страницам, наследующим этот шаблон, где они могут внедрить своё содержимое. Давайте определим дочернее представление, которое будет использовать этот макет и выводить его основной контент. === Определяем дочернее представление === Отлично. Макет нашего сайта завершён. Теперь мы должны определить представление, которое содержит форму создания новой задачи, а также таблицу со списком всех существующих задач. Давайте определим это представление в файле %%(t)resources/views/tasks/index.blade.php%%, оно будет соответствовать методу %%(t)index%% в нашем %%(t)TaskController%%. Мы пропустим небольшую часть Bootstrap CSS и сфокусируемся на важном. Помните, вы можете скачать весь исходный код этого приложения с ((https://github.com/laravel/quickstart-intermediate GitHub)): %% @extends('layouts.app') @section('content')
@include('common.errors')
{{ csrf_field() }}
@endsection %% ==== Несколько поясняющих замечаний ==== Прежде чем двигаться дальше, давайте немного поговорим об этом шаблоне. Во-первых, директива %%@extends%% сообщает Blade, что мы используем макет, который мы определили в %%(t)resources/views/layouts/app.blade.php%%. Все содержимое между %%@section('content')%% и %%@endsection%% будет добавлено вместо строчки директивы %%@yield('content')%% в макете %%(t)app.blade.php%%. Директива %%@include('common.errors')%% загрузит шаблон, расположенный в %%(t)resources/views/common/errors.blade.php%%. Он пока не определён, но скоро мы это сделаем! Итак, мы определили основной макет и представление для нашего приложения. Давайте вернём это представление из метода %%(t)index%% контроллера %%(t)TaskController%%: %% /** * Отображение списка всех задач пользователя. * * @param Request $request * @return Response */ public function index(Request $request) { return view('tasks.index'); } %% Теперь мы готовы добавить код в наш метод контроллера маршрута %%(t)POST /task%%, чтобы обработать входящие данные из формы и добавить новую задачу в БД. == Добавление задач == === Проверка ввода === Теперь, когда у нас есть форма на нашем представлении, мы должны добавить код к нашему методу %%(t)TaskController@store%%, чтобы проверить входящие данные из формы и создать новую задачу. Во-первых, давайте проверим ввод. Для этой формы мы создадим обязательное поле %%(t)name%% и зададим, что оно должно содержать не более %%(t)255%% символов. Если проверка не пройдёт, то мы перенаправим пользователя назад к URL %%(t)/tasks%%, а также возвратим ему в ((/docs/v5/session сессию)) его введённые данные с указанием на ошибки: %%(php) /** * Создание новой задачи. * * @param Request $request * @return Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:255', ]); // Создание задачи... } %% Если вы создавали приложение по ((/docs/v5/quickstart краткому руководству)), то могли заметить, что код валидации там другой. Так как мы находимся в контроллере, мы можем использовать удобный типаж %%(t)ValidatesRequests%%, который включён в базовый контроллер Laravel. Этот типаж представляет простой метод %%(t)validate%%, который принимает запрос и массив правил валидации. Нам даже не нужно самим определять результат валидации и даже не нужно вручную делать перенаправление. Если валидация не пройдена для заданных правил, пользователь будет автоматически перенаправлен туда, откуда он пришёл, и ошибки будут автоматически высвечены в сессии. Отлично! ==== Переменная %%$errors%% ==== Помните, что мы использовали директиву %%@include('common.errors')%% в нашем представлении, чтобы отобразить ошибки ввода формы. Представление %%common.errors%% позволяет нам легко показывать ошибки ввода в одинаковом формате на всех наших страницах. Давайте определим содержимое этого представления: %% @if (count($errors) > 0)
Упс! Что-то пошло не так!

@endif %% .(alert) Переменная %%$errors%% доступна в **любом** представлении Laravel. Если не будет ошибок ввода, она просто будет пустым экземпляром %%ViewErrorBag%%. === Создание задачи === Теперь, когда обрабатывается ввод данных, давайте создадим новую задачу, продолжая заполнять наш маршрут. Как только новая задача будет создана, мы перенаправим пользователя назад к URL %%(t)/tasks%%. Чтобы создать задачу, мы будем использовать мощность Eloquent отношений. Большинство Laravel отношений предоставляют метод %%(t)create%%, который принимает массив атрибутов и автоматически устанавливает значение внешнего ключа на соответствующей модели перед сохранением в базе данных. В этом случае метод %%(t)create%% автоматически установит свойство %%(t)user_id%% данной задачи на ID текущего аутентифицированного пользователя, к которому мы обращаемся с помощью %%(php)$request->user()%%: %% /** * Создание новой задачи. * * @param Request $request * @return Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required|max:255', ]); $request->user()->tasks()->create([ 'name' => $request->name, ]); return redirect('/tasks'); } %% Отлично! Теперь мы можем создавать задачи. Давайте продолжим создание нашего представления, добавив список всех существующих задач. == Отображение существующих задач == Во-первых, мы должны отредактировать наш метод %%(t)TaskController@index%%, чтобы передать все существующие задачи в представление. Функция %%view()%% принимает массив данных вторым параметром, который будет доступным для представления. Каждый ключ массива станет переменной в представлении. Например, мы можем сделать так: %% /** * Показать список всех задач пользователя. * * @param Request $request * @return Response */ public function index(Request $request) { $tasks = $request->user()->tasks()->get(); //для версии 5.1 //$tasks = Task::where('user_id', $request->user()->id)->get(); return view('tasks.index', [ 'tasks' => $tasks, ]); } %% Тем не менее, давайте рассмотрим некоторые возможности внедрения зависимостей от Laravel, чтобы внедрить %%(t)TaskRepository%% в наш %%(t)TaskController%%, который мы будем использовать для доступа ко всем нашим данным. === Внедрение зависимостей === Сервис-контейнер Laravel является одной из самых мощных возможностей всего фреймворка. После прочтения базового руководства, не забудьте прочитать всю документацию по контейнеру. ==== Создание репозитория ==== Как мы уже упоминали ранее, мы хотим определить %%(t)TaskRepository%%, который содержит логику доступа ко всем данным для модели %%(t)Task%%. Это будет особенно полезно, если приложение будет расти, и вам понадобится повсеместно использовать Eloquent запросы в приложении. Итак, давайте создадим папку %%(t)app/Repositories%% и добавим класс %%(t)TaskRepository%%. Помните, что все %%(t)app%% папки Laravel автоматически загружаются с помощью стандарта автоматической загрузки PSR-4, так что вы можете создать сколько угодно дополнительных каталогов: %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) ~%% tasks() ->orderBy('created_at', 'asc') ->get(); } } ~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) ~%% id) ->orderBy('created_at', 'asc') ->get(); } } ~%% %% ==== Внедрение репозитория ==== Как только наш репозиторий определён, мы можем просто передать в конструктор наш %%(t)TaskController%% и использовать его в нашем маршруте %%(t)index%%. Так как Laravel использует контейнер, чтобы разрешить все контроллеры, наши зависимости будут автоматически внедрены в экземпляр контроллера: %% middleware('auth'); $this->tasks = $tasks; } /** * Показать список всех задач пользователя. * * @param Request $request * @return Response */ public function index(Request $request) { return view('tasks.index', [ 'tasks' => $this->tasks->forUser($request->user()), ]); } } %% === Отображение задач === Когда данные переданы, мы можем обращаться к задачам в нашем представлении %%(t)tasks/index.blade.php%% и выводить их на экран таблицей. Blade-конструкция %%@foreach%% позволяет нам кратко писать циклы, которые компилируются в молниеносный простой PHP-код: %% @extends('layouts.app') @section('content') @if (count($tasks) > 0)
Текущая задача
@foreach ($tasks as $task) @endforeach
Task  
{{ $task->name }}
@endif @endsection %% Наше приложение почти готово. Но у нас нет способа удалять наши существующие задачи, когда они завершены. Давайте добавим и это! == Удаление задач == === Добавление кнопки удаления задачи === Мы оставили отметку "TODO" в коде, где предположительно будет находиться наша кнопка. Давайте добавим кнопку удаления к каждой строке нашего списка задач в представлении %%(t)tasks/index.blade.php%%. Мы создадим маленькую однокнопочную форму для каждой задачи в списке. После нажатия кнопки приложению будет отправляться запрос %%(t)DELETE /task%%, который будет обращаться к методу %%(t)TaskController@destroy%%: %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) ~%%
{{ $task->name }}
{{ csrf_field() }} {{ method_field('DELETE') }}
~%% %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) ~%%
{{ $task->name }}
{{ csrf_field() }} {{ method_field('DELETE') }}
~%% %% ==== Примечание по спуфингу метода ==== Обратите внимание на то, что %%(t)method%% формы кнопки удаления объявлен как %%(t)POST%%, несмотря на то, что мы отвечаем на запрос, используя маршрут %%Route::delete%%. HTML-формы позволяют использовать только %%(t)GET%% и %%(t)POST%% методы HTTP. А нам нужен способ имитировать запрос %%(t)DELETE%% от формы. Мы можем имитировать запрос %%(t)DELETE%%, выводя результаты функции %%method_field('DELETE')%% в нашей форме. Эта функция генерирует скрытый ввод формы, который распознается Laravel и используется, чтобы переопределить вызываемый метод HTTP. Сгенерированное поле будет похоже на это: %% %% === Привязка модели маршрута === Теперь мы почти готовы определить метод %%destroy()%% в нашем %%(t)TaskController%%. Но для начала давайте пересмотрим наше объявление маршрута и метод контроллера для этого маршрута: %% Route::delete('/task/{task}', 'TaskController@destroy'); %% %%(DOCNEW 5.1=cdc24ba7426c5b11eb4d050706bd78c3ea4913cc 19.06.2016 20:08:01) Если не добавлять никакого дополнительного кода, то Laravel внедрит ID заданной задачи в метод %%(t)TaskController@destroy%%: ~%% /** * Уничтожить заданную задачу. * * @param Request $request * @param string $taskId * @return Response */ public function destroy(Request $request, $taskId) { // } ~%% Однако, в первую очередь в этом методе мы должны будем получить экземпляр %%(t)Task%% из базы данных, используя пришедший ID. Было бы неплохо, если б Laravel мог просто внедрить экземпляр Task, соответствующий этому ID? Давайте сделаем это возможным! В нашем файле %%(t)app/Providers/RouteServiceProvider.php%% в методе %%boot()%% давайте добавим следующую строку: ~%% $router->model('task', 'App\Task'); ~%% Эта небольшая строчка заставит Laravel извлечь модель %%(t)Task%%, соответствующую заданному ID, каждый раз, когда он видит %%{task}%% в объявлении маршрута. Теперь мы можем определить наш метод %%destroy()%%: %% %% /** * Уничтожить заданную задачу. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { // } %% %%(DOCNEW 5.2=6b0b057ae6de3c88cb29188459e38383c622ec23 8.12.2016 23:00:15) Поскольку переменная %%{task}%% в нашем маршруте совпадает с переменной %%$task%%, определённой в методе нашего контроллера, ((//docs/v5/routing#привязка неявная привязка модели)) Laravel автоматически внедрит экземпляр соответствующей модели %%(t)Task%%. %% === Авторизация === Теперь у нас есть экземпляр %%(t)Task%%, внедрённый в метод %%destroy()%%. Тем не менее, нет никакой гарантии того, что аутентифицированный пользователь на самом деле "владеет" данной задачей. Например, злоумышленник может сделать запрос на удаление задачи другого пользователя, передавая случайный ID задачи по URL %%(t)/tasks/{task}%%. Поэтому мы должны использовать возможности авторизации Laravel, чтобы быть уверенным, что аутентифицированный пользователь на самом деле является владельцем экземпляра %%(t)Task%%, который был внедрён в маршрут. ==== Создание политики ==== Laravel использует "политики" для организации логики авторизации в простых небольших классах. Как правило, каждая политика соответствует модели. Давайте создадим %%(t)TaskPolicy%%, используя команду Artisan, которая поместит сгенерированный файл в %%(t)app/Policies/TaskPolicy.php%%: %%(sh) php artisan make:policy TaskPolicy %% Следующим шагом будет добавление метода %%destroy()%% к политике. Этот метод получает экземпляр %%(t)User%% и экземпляр %%(t)Task%%. Метод должен просто проверить, соответствует ли ID пользователя %%(t)user_id%% задачи. Фактически, все методы политики должны возвращать %%(t)true%% или %%(t)false%%: %% id === $task->user_id; } } %% В конце нам надо связать нашу модель %%(t)Task%% с %%(t)TaskPolicy%%. Мы можем сделать это, добавив одну строчку к свойству %%$policies%% в файле %%(t)app/Providers/AuthServiceProvider.php%%. Она проинформирует Laravel о том, какая политика должна быть использована каждый раз, когда мы пытаемся авторизовать действие в экземпляре %%(t)Task%%: %% /** * Маппинг политики для приложения. * * @var array */ protected $policies = [ 'App\Task' => 'App\Policies\TaskPolicy', //для версии 5.1 //Task::class => TaskPolicy::class, ]; %% ==== Авторизация действия ==== Теперь, когда наша политика написана, давайте использовать ее в нашем методе %%destroy()%%. Все контроллеры Laravel могут вызвать метод %%authorize()%%, который представлен типажом %%(t)AuthorizesRequest%%: %% /** * Уничтожение заданной задачи. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { $this->authorize('destroy', $task); // Удаление задачи... } %% Давайте немного исследуем этот вызов метода. Первым параметром, переданным методу %%authorize()%%, является имя метода политики, который мы хотим вызвать. Второй параметр - экземпляр модели, который нас сейчас интересует. Помните, мы недавно сообщили Laravel, что наша модель %%(t)Task%% соответствует нашему %%(t)TaskPolicy%%. Значит фреймворк знает, с какой политикой выполнить метод %%destroy()%%. Текущий пользователь будет автоматически отправлен в метод политики. Таким образом, мы не должны будем вручную передавать его здесь. Если действие авторизовано, наш код будет продолжать выполняться как и всегда. Однако, если действие не авторизовано (метод политики %%destroy()%% вернул %%(t)false%%), то будет выдано исключение 403, и на экран пользователя будет выведена страница ошибки. .(alert) Существует несколько других способов взаимодействия с сервисами авторизации от Laravel. Обязательно ознакомьтесь с ними в ((/docs/v5/authorization полной документации по авторизации)). === Удаление задачи === Наконец, давайте добавим к нашему методу %%destroy()%% логику удаления текущей задачи. Мы можем использовать Eloquent-метод %%delete()%%, чтобы удалить заданный экземпляр модели в базе данных. Когда запись будет удалена, мы перенаправим пользователя назад к URL %%(t)/tasks%%: %% /** * Уничтожение заданной задачи. * * @param Request $request * @param Task $task * @return Response */ public function destroy(Request $request, Task $task) { $this->authorize('destroy', $task); $task->delete(); return redirect('/tasks'); } %%