Создание миграции в Laravel
Давайте создадим миграцию create_articles_table, которая будет создавать таблицу в базе данных articles с полями:
- id – индегтификатор
- title – заголовок статьи
- text – текст статьи
- created_at – дата создания статьи
- updated_at – дата обновления статьи
Для этого выполним в консоли следующую команду:
php artisan make:migration create_articles_table --create=articles
Теперь в метод up нашей только что созданной миграции (database/migrations/<дата_создания>_<id-миграции>_create_articles_table.php) добавим следующий код:
public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->text('text'); $table->timestamps(); }); }
И запускаем процесс миграции:
php artisan migrate
Отлично, миграция выполнена. Если перейдем в нашу базу данных, то увидим, что создана (помимо таблиц: migrations, password_resets и users) таблица articles.
Создание модели в Laravel
Теперь нам нужно создать модель для работы с нашей таблицей articles. Для этого выполним в консоли следующую команду:
php artisan make:model Article
И добавим в нашу модель (app/Article.php) следующий код:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Article extends Model { protected $fillable = [ 'title', 'text' ]; }
Создание контроллера в Laravel
Теперь давайте создадим контроллер ресурсов:
php artisan make:controller ArticleController --resource
Добавим роуты к этому контроллеру. Открываем файл routes/web.php и добавляем:
Route::resource('/article', 'ArticleController',['only' => ['index', 'store', 'show', 'destroy']]);
И давайте в методе index контроллера ArticleController добавим для теста:
public function index() { return "INDEX"; }
Перейдем <домен>/article. В моем случае это http://lara.loc/article
Отлично, работает.
Вывод всех статей.
За вывод всех статей отвечает метод index контроллера ArticleController. Давайте опишем его:
public function index() { $articles = Article::all(['id','title']); return view('index',['articles' => $articles]); }
Мы получаем все записи из таблицы articles (но получаем только поля id и title) и передаем все в шаблон index.blade.php и не забываем добавить:
use App\Article;
Давайте создадим шаблон index.blade.php в каталоге resources/view и поместим в него следующий код:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>Список статей</title> <!-- Bootstrap --> <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <h1>Список статей</h1> <div class='row'> <button type="button" class="btn btn-primary btn-lg pull-right" data-toggle="modal" data-target="#addArticle"> Добавить статью </button> </div> <br /> <div class='row @if(count($articles)!= 0) show @else hidden @endif' id='articles-wrap'> <table class="table table-striped "> <thead> <tr> <th>ID</th> <th>Заголовок</th> <th></th> </tr> </thead> <tbody> @foreach($articles as $article) <tr> <td>{{ $article->id }}</td> <td><a href="{{ route('article.show', ['id' => $article->id]) }}">{{ $article->title }}</a></td> <td><a href="" class="delete" data-href=" {{ route('article.destroy',$article->id) }} ">Удалить</a></td> </tr> @endforeach </tbody> </table> </div> <div class="row"> <div class="alert alert-warning @if(count($articles) != 0) hidden @else show @endif" role="alert"> Записей нет</div> </div> </div> <!-- Modal --> <div class="modal fade" id="addArticle" tabindex="-1" role="dialog" aria-labelledby="addArticleLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="addArticleLabel">Добавление статьи</h4> </div> <div class="modal-body"> <div class="form-group"> <label for="title">Заголовок</label> <input type="text" class="form-control" id="title"> </div> </div> <div class="modal-body"> <div class="form-group"> <label for="text">Текст</label> <textarea class="form-control" id="text"></textarea> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button> <button type="button" class="btn btn-primary">Сохранить</button> </div> </div> </div> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="{{ asset('js/bootstrap.min.js') }}"></script> </body> </html>
Проверяем, что получилось.
Все работает. У нас записей в таблице пока нет. Давайте реализуем метод добавления статьи.
Добавление статьи с помощью ajax запроса
На странице со списком статей у нас есть кнопка, при нажатии на которую появляется модальное окно.
В данном окне мы вводим данные новой статьи. А при нажатии кнопки «Сохранить» передаем данные с помощью ajax для сохранения.
Давайте напишем JavaScript, который при клике по «Сохранить» будет отправлять ajax запрос на адрес <домен>/article (в моем случае http://lara.loc/article), а данные передавать методом POST.
Первое, что сделаем – это добавим к кнопке «Сохранить» id=«save». И напишем небольшой код на JavaScript. В конце файла index.blade.php, после подключения скриптов, добавим:
<script> $(function() { $('#save').on('click',function(){ var title = $('#title').val(); var text = $('#text').val(); $.ajax({ url: '{{ route('article.store') }}', type: "POST", data: {title:title,text:text}, headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }, success: function (data) { $('#addArticle').modal('hide'); $('#articles-wrap').removeClass('hidden').addClass('show'); $('.alert').removeClass('show').addClass('hidden'); var str = '<tr><td>'+data['id']+ '</td><td><a href="/article/'+data['id']+'">'+data['title']+'</a>'+ '</td><td><a href="/article/'+data['id']+'" class="delete" data-delete="'+data['id']+'">Удалить</a></td></tr>'; $('.table > tbody:last').append(str); }, error: function (msg) { alert('Ошибка'); } }); }); }) </script>
Думаю, что код пояснять не нужно. Просто тут мы передаем методом POST две переменные title и text на адрес, который определяем по имени роута.
Теперь давайте опишем метод контроллера, который вызывается этим роутом (в нашем случае это контроллер ArticleController и метод store). Добавим в метод store следующий код:
$res = Article::create(['title' => $request->title, 'text' => $request->text]); $data = ['id' => $res->id, 'title' => $request->title, 'text' => $request->text]; return $data;
Можем проверять. Давайте создадим первую статью.
Статья добавлена. Если мы откроем нашу таблицу в базе данных, то увидим запись.
Давайте реализуем просмотр статьи.
Просмотр статьи
Для просмотра статьи у нас есть метод show контроллера ArticleController, давайте добавим следующий код:
public function show($id) { $article = Article::find($id); return view('show',['article' => $article]); }
Мы в базе ищем статью по ее id, и все возвращаем в шаблон show.blade.php. Давайте создадим шаблон show.blade.php и добавим в него следующий код. (Напомню, что шаблон, в нашем случае, должен находиться в resources/view)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>{{ $article->title }}</title> <!-- Bootstrap --> <link href="{{ asset('css/bootstrap.min.css') }}" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title">{{ $article->title }}</h3> </div> <div class="panel-body"> {{ $article->text }} </div> </div> </div> </body> </html>
Давайте проверим. На странице со списком статей кликаем по ссылке с названием статьи:
Отлично. По нашей задаче осталось реализовать только удаление статьи.
Удаление статьи методом ajax.
За удаление статьи у нас отвечает метод destroy контроллера ArticleController. Давайте опишем этот метод.
public function destroy ($ id) { Article::find ($id)->delete(); return 'ok'; }
Теперь в шаблоне index.blade.php нам необходимо реализовать javascript, который будет передавать ajax данные методу для удаления. Но данные передаются методом DELETE.
Давайте приступим к реализации.
Добавим в секцию <script> следующий скрипт:
$('body').on('click','.delete',function(e){ e.preventDefault(); var url = $(this).data('href'); var el = $(this).parents('tr'); $.ajax({ url: url, type: "POST", headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }, success: function (data) { el.detach(); }, error: function (msg) { alert('Ошибка'); } }); });
Давайте проверим, что у нас получилось. Добавим еще несколько статей и попробуем их удалить.
Отлично все работает.
Заключение.
Мы свами на практике реализовали ajax запросы в Laravel. Создали контроллер ресурсов, в котором реализовали создание статьи по ajax запросу, просмотр статьи (обычный get запрос) и удаление статьи ajax запросом.
Да, при добавлении статьи мы могли к полю text подключить WYSIWYG, как это сделать описано в статье «Подключаем текстовый (wysiwyg) редактор к Laravel», также мы не сделали валидацию при добавлении статей. Но цель статьи была не в этом и цель мы достигли: использование AJAX запросов в Laravel.