Laravel Livewireとは
CALEB PORZIOが作った Laravel用パッケージ
https://github.com/calebporzio/laracasts-livewire-datatable
https://laravel-livewire.com/
動的なテーブル表示を簡単につくれる
2019/11/26 に CALEB PORZIOがLaracastsにチュートリアル動画をアップした。
https://laracasts.com/series/guest-spotlight/episodes/3
CALEB PORZIO の チュートリアル動画を参考にして Books動的テーブル表示を作ってみました。view blade, Controller, Modelはほぼ彼のチュートリアル動画の内容と同じです。
CALEB PORZIOのgithubのサンプルはMySQLで動かない
CALEB PORZIOはsqliteで 動作確認をしているが .envのDB_CONNECTIONをmysqlに変更すると動かない。原因はapp/Http/Livewire/ContactsTable.phpがorder by ``のようなSQLを発行してしまうからで13行目にある public $sortField; を public $sortField = 'id';などに変更するとMySQLでも動作するようになる。
Laravel project
Table
tablesとauthorsテーブルを用意してseederでbooksを500レコード authorsを3レコード作成。適当なfactoryも作る。 php artisan migrate; php artisan db:seed でデータを用意。
class CreateBooksTable extends Migration {
public function up() {
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title'); // ←追加
$table->unsignedInteger('author_id'); // ←追加
$table->timestamps();
});
}
}
class CreateAuthorsTable extends Migration {
public function up() {
Schema::create('authors', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name'); // ←追加
$table->timestamps();
});
}
}
class BooksTableSeeder extends Seeder {
public function run()
{
factory(\App\Book::class, 500)->create(); // ←追加
}
}
class AuthorsTableSeeder extends Seeder {
public function run()
{
factory(\App\Author::class, 3)->create(); // ←追加
}
}
LivewireでBooks一覧画面を作る
Livewireのインストール
コンポーザーでインストール
composer require livewire/livewire
make:livewireでbladeとClassを作る
php artisan make:livewire books-table
以下のファイルが作られる
CLASS: app/Http/Livewire/BooksTable.php
VIEW: resources/views/livewire/books-table.blade.php
routes/web.php
一行だけ追加
Route::get('books', 'BooksController');
app/Author.php
booksテーブルとのリレーションだけ追加。
class Author extends Model
{
protected $guarded = [];
public function books()
{
return $this->hasMany(Book::class);
}
}
app/Book.php
Authorテーブルへのリレーションを追加。
検索メソッドを追加。(CALEB PORZIOのContacts.phpを参考にしました。ほぼ同じです。)
class Book extends Model
{
protected $guarded = [];
public static function search(string $query)
{
$res = empty($query) ? static::query()
: static::where('title', 'like', '%' . $query . '%');
return $res;
}
public function author()
{
return $this->belongsTo(Author::class);
}
}
app/Http/Controllers/BooksController.php
public function __invoke(Request $request)
{
$books = \App\Book::paginate(); // ←この処理使われていない. $booksはBooksTable.phpで取得するから
return view('books', ['books' => $books]);
}
app/Http/Livewire/BooksTable.php
CALEB PORZIOのapp/Http/Livewire/ContactsTable.phpとほぼ同じです。booksテーブル用に少しだけ変更しました。
class BooksTable extends Component
{
use withPagination;
public $perPage = 10;
public $search = '';
public $sortField = 'id';
public $sortAsc = true;
public function clear() {
$this->search = '';
}
public function sortBy($field) {
if ($this->sortField === $field) {
$this->sortAsc = !$this->sortAsc;
} else {
$this->sortAsc = true;
}
$this->sortField = $field;
}
public function render()
{
$books = \App\Book::search($this->search)
->orderBy($this->sortField, $this->sortAsc ? 'asc' : 'desc')
->paginate($this->perPage);
return view('livewire.books-table', ['books' => $books]);
}
}
resources/views/books.blade.php
@livewireAssetsを追加して
@livewire('books-table) でbooks-table.blade.phpを読み込みます。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Books</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.css">
@livewireAssets
</head>
<body style="padding:8px;">
<h1>Books</h1>
<div class="container pt-4">
@livewire('books-table')
</div>
</body>
</html>
/resources/views/livewire/books-table.blade.php
テーブル表示のviewを書きます
wire:model、wire:click.preventの設定があるところが app/Http/Livewire/BooksTable.php と連携するところです。
の値はBooksTable.phpの$searchと同期します。
- Books用に変更してありますが、CALEB PORZIOの resources/views/livewire/contacts-table.blade.php とほぼ同じです。 CALEB PORZIOのチュートリアル動画を参照してください。
<div>
<div class="row mb-4">
<div class="col form-inline">
Per Page:
<select wire:model="perPage" class="form-control">
<option>10</option>
<option>15</option>
<option>25</option>
</select>
</div>
<div class="col">
<input wire:model="search" class="form-control" type="text" placeholder="Search books...">
</div>
</div>
<div class="row">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>
<a wire:click.prevent="sortBy('title')" role="button" href="#">
Title
</a>
</th>
<th>
<a wire:click.prevent="sortBy('author_id')" role="button" href="#">
Author
</a>
</th>
</tr>
</thead>
<tbody>
@foreach ($books as $book)
<tr>
<td>{{ $book->id }}</td>
<td>{{ $book->title }}</td>
<td>{{ $book->author['name'] }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="row">
<div class="col">
{{ $books->links() }}
</div>
<div class="col text-right text-muted">
Showing {{ $books->firstItem() }} to {{ $books->lastItem() }} out of {{ $books->total() }} results
</div>
</div>
</div>
動作確認
php artisan serve
ブラウザで実際に動かしてみる。
すごい!動く!JavaScriptを1行も書かずに!
CALEB PORZIOすごい!
CALEB PORZIOのチュートリアル動画
https://laracasts.com/series/guest-spotlight/episodes/3