0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravel + SQLiteでシンプルなブログアプリを作っていく

Last updated at Posted at 2020-05-31

#はじめに
以前の投稿、Laravel + SQLite 準備編からの続きで、開発を進めます。

ドットインストール Laravel 5.5入門の内容に沿ってシンプルなブログアプリ開発を行います。

#環境
[VisualStudioCode]
(https://code.visualstudio.com)

Laravel Framework 7.12.0

#マイグレーションの設定

まず記事に関するモデルから作ります。

Terminal
$ php artisan make:model Post --migration

モデルはartisanコマンドを使えば良いのでphp artisanとします。
make:modelとしてモデル名は記事のModelなのでPostとします。

その後にバージョン管理するためのマイグレーションファイルも作るので、
--migrationというオプションを付けます。

こうするとModelが作られてmigrationファイルも作られます。


migrationファイルを開いてデータベース構造の設定をします。
migrationファイルはdatabaseの中のmigrationsにあります。
migrationファイルにはup()とdown()というメソッドがあります。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

up()→このマイグレーションで行いたい処理
down()→それを巻き戻すための処理

これらがあることでデータベース構成を変更したり、その変更を取り消したりすることが出来るので、結果としてデータベース構成のバージョン管理ができるという仕組みです。

upメソッドは自動的にmodelを複数形にしたテーブル名にしてくれてidとtimestampsを設定してくれています。
idは連番で付けられる主キーです。

timestampsはcreated_at updated_atというcolumnを作ってくれて作成日時と更新日時を自動で管理してくれる仕組みになっています。

columnを追加したいので、titleとbodyというcolumnにします。

$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();

columnの種類
SQLでいうところのvarcharはstringで設定していくのでstring('title')
bodyはテキストで設定したいのでtext('body')

参考:varchar

可変長の文字列です。可変長とは「長さが決まっていない」という意味で、varchar(10)に2バイトを格納すると、10バイトではなく2バイト使用します。
最大8,000バイト。文字データ型として最もよく使われるデータ型です。

このマイグレーションファイルの中身を実行します。

Terminal
$ php artisan migrate

SQLite でテーブルが作られたか確認。

Terminal
$ sqlite3 database/database.sqlite
Terminal
sqlite> .schema posts
Terminal
sqlite> .quit

確認できたらこれでOKです。

#Modelのインタラクティブな操作
LaravelはEloquentモデルと呼ばれていてSQLを意識しなくても直感的にデータが操作できるようになっています。

Eloquent:利用の開始 5.7 Laravel - ReaDouble

Eloquent ORMはLaravelに含まれている、美しくシンプルなアクティブレコードによるデーター操作の実装です。それぞれのデータベーステーブルは関連する「モデル」と結びついています。モデルによりテーブル中のデータをクエリできますし、さらに新しいレコードを追加することもできます。

Postモデルを作ったのでphp artisan tinkerというコマンドを使いインタラクティブに操作してみます。

Terminal
$ php artisan tinker

まずはレコードを挿入します。
インスタンスを作りsaveメソッドを使います。

インスタンスの作り方はデフォルトで名前空間がAppになっているのでnew App\Post()とします。

名前空間の概要 - Manual - PHP

Terminal
>>> $post = new App\Post()
=> App\Post {#3054}

他にも設定していきます。

Terminal
>>> $post->title = 'title 1'; $post->body = 'body 1';
=> "body 1"
Terminal
>>> $post->save();
=> true
>>> 

このようにtrueと出れば正常に処理が終了したという意味になります。

格納したデータを確認する
APP\Post::all();
こちらのコマンドを使います。

Terminal
>>> APP\Post::all();
=> Illuminate\Database\Eloquent\Collection {#3781
     all: [
       App\Post {#3780
         id: "1",
         title: "title 1",
         body: "body 1",
         created_at: "2020-05-24 07:40:04",
         updated_at: "2020-05-24 07:40:04",
       },
     ],
   }

もっとシンプルな表示でみたい場合
App\Post::all()->toArray();

Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
   ]

tinker終了
exit

Terminal
>>> exit
Exit:  Goodbye

SQLiteでも確認する

Terminal
$ sqlite3 database/database.sqlite
Terminal
sqlite> select * from posts;

先ほどのtitle1が入っているか確認

Terminal
1|title 1|body 1|2020-05-24 07:40:04|2020-05-24 07:40:04

Eloquentモデルを使えばSQLを特に意識しなくてもこのようにデータが扱えます。

Terminal
sqlite> .exit

終了
#Mass Assignmentの設定
Eloquentモデルをいじっていきたいのでまずtinkerを使います。

Terminal
$ php artisan tinker

データを格納する際にインスタンスを作ってsaveとしていましたが、

Terminal
App\Post::create(['title'=>'title 2', 'body'=>'body 2']);

これでそれぞれにデータを与えて一気に追加することも可能です。
しかしそのまま実行しても以下のようなエラーになります。

Terminal
Illuminate/Database/Eloquent/MassAssignmentException with message 'Add [title] to fillable property to allow mass assignment on [App/Post].'

MassAssignment エラー: 意図しないリクエストによって悪意のあるデータが挿入されてしまう脆弱性

これを実行するにはLaravelでデフォルト設定を変える必要があります。

モデルで設定をします。
Modelはappの中にあるのでapp>Post.phpを編集します。

class Post extends Model {}の中に

Terminal
protected $fillable = ['title', 'body'];

このcolumnの、titleとbodyにデータを挿入していい という設定になります。

設定を変えたのでtinkerをexitしてもう一度tinkerで入ります。

Terminal
>>> exit
Terminal
$ php artisan tinker

これで先ほどと同じコマンドを実行できます。

Terminal
>>> App\Post::create(['title'=>'title 2', 'body'=>'body 2']);
=> App\Post {#3935
     title: "title 2",
     body: "body 2",
     updated_at: "2020-05-24 08:37:32",
     created_at: "2020-05-24 08:37:32",
     id: 2,
   }

さらにApp\Post::create(['title'=>'title 3', 'body'=>'body 3']);と追加すれば3も挿入できます。

Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
   ]

#データの抽出
特定のidのデータを引っ張ってくる場合はfindにidを渡します。
idが3のデータを引っ張ってくるには、

Terminal
>>> App\Post::find(3)->toArray();
=> [
     "id" => 3,
     "title" => "title 3",
     "body" => "body 3",
     "created_at" => "2020-05-24T08:39:36.000000Z",
     "updated_at" => "2020-05-24T08:39:36.000000Z",
   ]

条件付きで抽出するにはwhereとgetを使います。
例えばidが1より大きいものをgetせよという命令はこのようにします。

Terminal
>>> App\Post::where('id', '>', 1)->get()->toArray();
=> [
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
   ]

このように2と3が抽出されています。

#データの並び替え
orderBy('created_at', 'desc') で新しい順に表示します。

Terminal
>>> App\Post::where('id', '>', 1)->orderBy('created_at', 'desc')->get()->toArray();
=> [
     [
       "id" => 3,
       "title" => "title 3",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T08:39:36.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]

SQLでいうところのlimitで、変数を制限するにはtakeを使います。

SQLデータ分析入門#4『LIMIT句を理解する』

指定したレコードを上限に、結果を引っ張ってくる

Terminal
>>> App\Post::where('id', '>', 1)->take(1)->get()->toArray(); 
=> [
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]

#データの更新
一旦Postの3を$postに入れます。

Terminal
>>> $post = App\Post::find(3);
=> App\Post {#4008
     id: "3",
     title: "title 3",
     body: "body 3",
     created_at: "2020-05-24 08:39:36",
     updated_at: "2020-05-24 08:39:36",
   }

$post->title を更新します。

Terminal
>>> $post->title = 'title 3 updated';
=> "title 3 updated"
Terminal
>>> $post->save();
=> true

これでデータベースに反映したので確認します。

Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
     [
       "id" => 3,
       "title" => "title 3 updated",
       "body" => "body 3",
       "created_at" => "2020-05-24T08:39:36.000000Z",
       "updated_at" => "2020-05-24T09:20:06.000000Z",
     ],
   ]

title 3 updatedに変わっているのでOKです。

#データの削除
deleteを使います。

以下のように今$postがidが3のデータになっています。

Terminal
>>> $post
=> App\Post {#4008
     id: "3",
     title: "title 3 updated",
     body: "body 3",
     created_at: "2020-05-24 08:39:36",
     updated_at: "2020-05-24 09:20:06",
   }

これを削除します。

Terminal
>>> $post->delete();
=> true

全件表示で確認します。

Terminal
>>> App\Post::all()->toArray();
=> [
     [
       "id" => 1,
       "title" => "title 1",
       "body" => "body 1",
       "created_at" => "2020-05-24T07:40:04.000000Z",
       "updated_at" => "2020-05-24T07:40:04.000000Z",
     ],
     [
       "id" => 2,
       "title" => "title 2",
       "body" => "body 2",
       "created_at" => "2020-05-24T08:37:32.000000Z",
       "updated_at" => "2020-05-24T08:37:32.000000Z",
     ],
   ]

idが1と2だけになっています。

#Controller
Postモデルにいくつかデータを格納できたので、そのデータをブラウザで表示します。
それにはどのURLでどのような処理をするかの設定をする必要があります。

その設定をルーティングと呼び、routesフォルダの中のweb.phpで設定できます。

デフォルトの以下の部分は今回は使わないので削ります。

routes>web.php
Route::get('/', function () {
    return view('welcome');
});

URLに/をつけてgetでアクセスした時のroutingを作る場合はまず、
Route::get('/', '')のように書いて、その後に行いたい処理を書いていきます。
PostsController@indexアクションを実行せよとしていきます。

routes>web.php
Route::get('/', 'PostsController@index');

Controllerが必要になるので作っていきます。
artisanコマンドを使うのでphp artisan make:controllerとしてPostsControllerという名前にします。

Terminal
$ php artisan make:controller PostsController
Controller created successfully.

Controllerが作られました。

Controllerはapp>Http>ControllersにPostsController.phpができているので編集していきます。

helloと表示してみます。
表示する内容を返せばいいのでreturn "hello";のようにします。

app>Http>Controllers>PostsController.php
extends Controller
{
  public function index() {
    return "hello";
  }
}

確認していきたいのでサーバーを立ち上げます。
サーバーを立ち上げるにあたってIPアドレスが必要になるので、
$ ifconfig で調べられます。
inetの隣に4つ並んでいるものがローカルIPです。

ホストを指定する必要があるので、先程のIPアドレスを入れて--host 192.XXX.X.XX -- portを8000番で立ち上げてます。

Terminal
 $ php artisan serve --host 192.168.X.XXX --port 8000

実行

Terminal
Laravel development server started: http://192.168.X.XXX:8000

アクセス先のURLが出てきますので確認します。

helloと出てくればOKです。

以上がroutingを設定してその処理をController辺りに作成するという流れでした。

#View
viewを用意してそこにデータを入れていきます。
resourcesの中のViewsの中に作ります。

フォルダ名:Postに関するviewをまとめるのでpostsフォルダを用意します。
その中にAction名に対応したviewの名前を付けます。

ファイル名:indexアクションなのでindex。LaravelではBladeというテンプレートエンジンが使えるので、index.blade.phpとなります。

Laravel 5.5 Bladeテンプレート

BladeはシンプルながらパワフルなLaravelのテンプレートエンジンです。他の人気のあるPHPテンプレートエンジンとは異なり、ビューの中にPHPを直接記述することを許しています。全BladeビューはPHPへコンパイルされ、変更があるまでキャッシュされます。つまりアプリケーションのオーバーヘッドは基本的に0です。Bladeビューには.blade.phpファイル拡張子を付け、通常はresources/viewsディレクトリの中に設置します。

内容の編集:emmetの機能でhtml5のテンプレートを貼り付けたら、titleと文字コードを編集。

bodyの方では、中身を後で中央揃えにします。
<div class="container">で囲っておき、見出し(h1)と記事の一覧(li)を作っていきます。

resources>views>posts>index.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Blog Posts</title>
</head>
<body>
  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      <li><a href="">title</a></li>
      <li><a href="">title</a></li>
      <li><a href="">title</a></li>
    </ul>
  </div>
</body>
</html>

これでviewができたのでControllerの方でこのviewを指定します。

app>Http>Controllers>PostsController.php
extends Controller
{
  public function index() {
    // return "hello"; 編集
    return view('posts.index');
  }
}

viewを使うにはreturn viewの後にviewの名前を指定します。
Action名と同じにしたのでposts.indexとします。
フォルダの区切りは .(ドット) になっている点に注意します。

ブラウザをリロードして確認

スクリーンショット 2020-05-25 10.22.44.png このようにviewが反映されてればOKです。

#データの抽出
データを入れるため、まずはデータの取得からしていきます。

データを取得するにはEloquentの命令を使います。
$posts = \App\Post::all();
とすると全件を取得することが出来ます。
しかし名前空間が長くなるので、上の方でuse App\Post;を使います。

app>Http>Controllers>PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostsController extends Controller
{
  public function index() {
    $posts = Post::all();
    dd($posts->toArray()); // dump die
    return view('posts.index');
  }
}

データが取得できたかどうかは、Laravelで用意されているdd()という命令を使って確かめます。
ddはdump dieの略で結果を出力して処理をその場で終了する命令です。
配列で見やすく表示させたいのでdd($posts->toArray());としています。
スクリーンショット 2020-05-25 10.45.18.png
こうしてブラウザで確認するとtitle1とtitle2のデータが取れています。

あとは記事を新しい順に並べたいのでorderByで並べ替えます。
Post::orderBy('created_at', 'desc')->get();

これでいいのですが、このcreated_atで新しい順に取ってくるという処理はよく行うので、
Laravelではlatest()という書き方も用意されていて
Post::latest()->get();で同じ意味になります。

app>Http>Controllers>PostsController.php
class PostsController extends Controller
{
  public function index() {
    // $posts = Post::orderBy('created_at', 'dest')->get;
    $posts = Post::latest()->get();
    dd($posts->toArray()); // dump die
    return view('posts.index');
  }
}

ブラウザで確認します。
スクリーンショット 2020-05-25 11.01.12.png
title2のほうが上に来ているのがわかります。
これでデータの抽出ができました。

#データをViewに埋め込む

$postsでデータの取得ができたのでこれをviewの方に渡していきます。
return view()の第2引数に渡します。

'posts' => $postsとすると$postsの内容をviewの中でpostsという名前で使うことが出来ます。

もしくはwith('post', '$posts');でも全く同じ意味になります。

class PostsController extends Controller
{
  public function index() {
    $posts = Post::latest()->get();
    // return view('posts.index', ['posts' => $posts]);
    return view('posts.index')->with('posts', $posts);
  }
}

viewの方でこのpostsを使っていきます。

Bladeでは@foreachという制御構造を使えるので@foreach(\$posts as \$post)として、この$postを使ってループを展開していきます。

resources>views>posts>index.blade.php
<div class="container">
    <h1>Blog Posts</h1>
    <ul>
      @foreach ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @endforeach
    </ul>
  </div>

これで$postsが無くなるまで$postでひとつひとつの記事を表すことが出来るので値を埋め込みます。

値の埋め込みには二重波括弧を使うとエスケープもします。
{{ $post->title }}で$postのtitleを表示をします。

ブラウザを確認します。

スクリーンショット 2020-05-25 11.25.45.png

title2, title1 となっています。

もしこちらの$postsの中身が空だったら、と書きたい場合

@forelseという構文を使います。
そうすると、@emptyという命令が使えるので@emptyの後に、このデータが空だった時のテンプレートを入れ込むことが出来ます。

No posts yetと表示させることにします。

  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      @forelse ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @empty
      <li>No posts yet</li>
      @endforelse
    </ul>
  </div>

一旦$postsを空にします。

class PostsController extends Controller
{
  public function index() {
    // $posts = Post::latest()->get();
    $posts = [];
    // return view('posts.index', ['posts' => $posts]);
    return view('posts.index')->with('posts', $posts);
  }
}
スクリーンショット 2020-05-25 11.43.00.png 空のときの表示ができました。 確認できたら`$posts = [];`は戻しておきます。

BladeではHTMLに出力したくないコメントは{{-- --}}で囲みます。

  <div class="container">
    <h1>Blog Posts</h1>
    <ul>
      {{--
      @foreach ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @endforeach
      --}}
      @forelse ($posts as $post)
      <li><a href="">{{ $post->title }}</a></li>
      @empty
      <li>No posts yet</li>
      @endforelse
    </ul>
  </div>

スタイルを整える
CSSを読み込むリンクタグを入れます。
<link rel="stylesheet" href="/css/styles.css">

CSSやJavaScriptや画像はpublicフォルダの中に作っていきます。

public>css>styles.css
body {
  font-family: Verdana, sans-serif;
  font-size: 14px;
}

.container {
  width: 400px;
  margin: 20px auto;
}

h1 {
  font-size: 16px;
  padding-bottom: 10px;
  margin-bottom: 15px;
  border-bottom: 1px solid #ddd;
}

ul >li {
  margin-bottom: 5px;
}

以下のような見た目になればOKです。
スクリーンショット 2020-05-25 13.00.12.png

#記事の詳細画面の作成
記事の一覧ができたので、次は記事の詳細画面を作ります。
まずはroutingです。

URLとしてはgetでアクセスされたpostsの1や2を処理したいのですが、
ここにきた値をControllerに渡したい場合は波括弧を付けて変数名を書きます。

Controllerはshowアクションに渡します。
Route::get('/posts{id}', 'PostsController@show');

routes>web.php
<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', 'PostsController@index');
Route::get('/posts{id}', 'PostsController@show');

次にshowアクションを作ります。

Controllerの中に続きから書いていきます。

app>Http>Controllers>PostsController.php
public function index($id) {
    // $post = Post::find($id);
    $post = Post::findOrFail($id);
    return view('posts.show')->with('post', $post);
  }

web.phpのURLのパラメーターから渡ってきた値は引数で受け取ることが出来るので$idとします。

データを引っ張ってくるのでPost::find($id)でいいのですが$idでデータが見つからなかった場合に、例外を返したいのでその場合はfindOrFail()という命令を使います。

そしてデータをviewに渡してあげれば良いので今回はposts.showというテンプレートに対してpostという名前で$postのデータを渡します。

app>Http>Controllers>PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostsController extends Controller
{
  public function index() {
    $posts = Post::latest()->get();
    return view('posts.index')->with('posts', $posts);
  }
  public function show($id) {
    $post = Post::findOrFail($id);
    return view('posts.show')->with('post', $post);
  }
}

viewを作りたいのでresourcesフォルダに行きます。

index.blade.phpを複製してshow.blade.phpを作り編集していきます。

head内タイトル変更

<title>{{ $post->title }}</title>

body内

resources>views>posts>show.blade.php
<body>
  <div class="container">
    <h1>{{ $post->title }}</h1>
    <p>{!! nl2br(e($post->body)) !!}</p>
  </div>
</body>

この部分について
<p>{!! nl2br(e($post->body)) !!}</p>

本文の方は改行が入ってくる可能性もあるので、改行をbrタグに変換したいです。
まずは二重波括弧ではなく、中身をエスケープしないで値を出力するための{{!! !!}}という命令を使います。

$post->bodyを入れたいので、一旦Laravelのe()ヘルパーでエスケープして、それをnl2br()で挟み改行をbrタグにします。


e()
https://readouble.com/laravel/5.5/ja/helpers.html#method-e

e関数は、PHPのhtmlspecialchars関数をdouble_encodeオプションにfalseを指定し、実行します。

echo e('<html>foo</html>');

// &lt;html&gt;foo&lt;/html&gt;

e()について
https://laraweb.net/knowledge/835/

HTMLエンティティ―(※ブラウザがHTMLとして処理せずにそのまま出力させるための代替コード)の実行

echo e('<strong>laravel</strong>');
//出力結果 ⇒ &lt;strong&gt;laravel&lt;/strong&gt;

nl2br()
https://www.php.net/manual/ja/function.nl2br.php

nl2br — 改行文字の前に HTML の改行タグを挿入する
説明
nl2br ( string $string [, bool $is_xhtml = TRUE ] ) : string
string に含まれるすべての改行文字 (\r\n、 \n\r、\n および \r) の前に 
 あるいは 
 を挿入して返します。

#Implicit Binding
記事の一覧から記事の詳細画面にリンクを張ります。

routingの設計通り/posts/{{ $post->id }}でもいいですが、

@forelse ($posts as $post)
li><a href="/posts/{{ $post->id }}">{{ $post->title }}</a></li>

URLを生成するための命令が他にもいくつかあります。

url()という命令を使う方法

<li><a href="{{ url('/$posts', $post->id }}">{{ $post->title }}</a></li>

これでも同じ意味になります。

もしくはControllerとActionからURLを生成することができるaction()という命令もあります。
その場合はPostsControllerのshowに対応するURLを生成する、という書き方ができます。

routingのパラメーターに渡す値は、第2引数以降に入れていけばいいので以下のようにします。

<li><a href="{{ action('PostsController@show', $post->id }}">{{ $post->title }}</a></li>

これで各titleをクリックすると以下のように詳細リンクに飛べるようになりました。
スクリーンショット 2020-05-25 14.49.32.png

URLから$idを受け取って、Controllerでその$idを元にモデルを引っ張ってくるという流れはよく行うので、暗黙的にモデルをデータに結びつけられるImplicit Bindingという仕組みも用意されています。

まずroutingを'/posts/{post}'にします。

routes>web.php
// Route::get('/posts{id}', 'PostsController@show');
Route::get('/posts{post}', 'PostsController@show');
app>Http>Controllers>PostsController.php
// public function show(Post $id) {
public function show(Post $post) {

これで自動的にこの$postにはURLから受け取ったidに対応するデータが格納されます。

なのでこの場合はidで引っ張ってくる必要がないのでこれでOKです。

  public function show(Post $post) {
    // $post = Post::findOrFail($id); // 削除
    return view('posts.show')->with('post', $post);
  }

さらにリンクの生成についても$post->id$postにするだけで、@postのidをパラメーターに渡してくれます。

resources>views>posts>index.blade.php
      <!-- <li><a href="{{ action('PostsController@show', $post->id) }}">{{ $post->title }}</a></li> -->
      <li><a href="{{ action('PostsController@show', $post) }}">{{ $post->title }}</a></li>

同じようにtitleから詳細リンクへの動作を確認することができます。
以上がImplicit Bindingです。

長くなるので続きは分けます。

後半は共通部分の部品化、編集やコメント機能などから進めていきます。

#Links
ドットインストール Laravel 5.5入門
https://dotinstall.com/lessons/basic_laravel_v2

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?