laravelでCRUDを理解するためにまたTodoを作った！


# LaravelでCRUDするのにやったこと

Laravelを使うための環境設定は別の記事で紹介します。

今回はXampp環境で最小構成のTodoを作成しました。

作成・修正を行ったファイルとその意味について整理します。

## フォルダが多くてきついと思っていた！

**一通り作ると結構すくないもんなんだな。**

<strong>使用ファイル

- マイグレーションファイル
- フロント用bladeファイル
- コントローラファイル
- ルーティングファイル：web.php
- modelファイル
- 使う人には.env

## マイグレーション：DBテーブルの作成

マイグレーションは、アプリフォルダ内にDBの構成を記録しておくファイルです。

xamppの環境下であればphp artisan migrateコマンドを打てば、DBが自動で作成されるため便利です。

今回は、テーブル名のposts、カラム名（id,title,content,timestamp）のDBを作成します。

<strong>database\migrationsフォルダの中にあるよ。

```php
<?php

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

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

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

### 尚、マイグレーションがうまくいかないときは、.envファイルをいじるよ！

以下参考まで。

```php
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:********************************************
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
 DB_DATABASE=laravel
 DB_DATABASE=laravel_posting_app
DB_USERNAME=root
DB_PASSWORD=
```

## bladeファイル：MVCのV（View）Laravelで使うhtmlはこのファイルに書き込みます。

hoge.blade.phpのように、ファイル名と拡張子の間にbladeという文字が挟まれます。

@foreachや@if等の制御文が書け、マスタッシュ構文{{}}にてDBの中身を出力したりできます。

<strong>resources\views\postsフォルダの中にあるよ！

Todoのいいところは大体のアプリの材料になるよ！

フロントのここら辺をいじれば、chatにも掲示板にもなるよ！

```php
 @foreach($posts as $post)
                 <div>
                     <div>
                         <h2>{{ $post->title }}</h2>
                         <p>{{ $post->content }}</p>  
                         <div>
                            <a href="{{ route('posts.show', $post) }}">詳細</a>                                
                            <a href="{{ route('posts.edit', $post) }}">編集</a>            
                            
                            <form action="{{ route('posts.destroy', $post) }}" method="post">
                                @csrf
                                @method('delete')                                        
                                <button type="submit">削除</button>
                            </form>
                        </div>
                     </div>
                 </div>
                @endforeach
```

### index.blade.php:初期表示画面

```php
`
<!DOCTYPE html>
 <html lang="ja">
 
 <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>投稿一覧</title>
 </head>
 
 <body>
     <header>
         <nav>
             <div>
           
             </div>
         </nav>
     </header>
     <a href="{{ route('posts.index') }}">投稿アプリ</a>            
     <main>
         <article>
             <div>                
                 <h1>投稿一覧</h1>
                 
                 @if (session('flash_message'))
                     <p>{{ session('flash_message') }}</p>
                 @endif
 
                 <div>
                     <a href="{{ route('posts.create') }}">新規投稿</a>                                   
                 </div>   
                 
                 @foreach($posts as $post)
                 <div>
                     <div>
                         <h2>{{ $post->title }}</h2>
                         <p>{{ $post->content }}</p>  
                         <div>
                            <a href="{{ route('posts.show', $post) }}">詳細</a>                                
                            <a href="{{ route('posts.edit', $post) }}">編集</a>            
                            
                            <form action="{{ route('posts.destroy', $post) }}" method="post">
                                @csrf
                                @method('delete')                                        
                                <button type="submit">削除</button>
                            </form>
                        </div>
                     </div>
                 </div>
                @endforeach 
             </div>
         </article>
     </main>
 
     <footer>        
         <p>&copy; 投稿アプリ All rights reserved.</p>
     </footer>
 </body>
 
 </html>
```

### create.blade.php:新規投稿画面

```php
`
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新規投稿</title>    
</head>

<body>
    <header>
        <nav>
            <div>                
                <a href="{{ route('posts.index') }}">投稿アプリ</a>          
            </div>
        </nav>
    </header>

    <main>
        <article>
            <div>                
                <h1>新規投稿</h1> 
                
                @if ($errors->any())
                    <div>
                        <ul>
                            @foreach ($errors->all() as $error)
                                <li>{{ $error }}</li>
                            @endforeach
                        </ul>
                    </div>
                @endif
                
                <div>
                    <a href="{{ route('posts.index') }}">&lt; 戻る</a>                                  
                </div>

                <form action="{{ route('posts.store') }}" method="post">
                    @csrf
                    <div>
                        <label for="title">タイトル</label>
                        <input type="text" name="title" value="{{ old('title') }}">
                    </div>
                    <div>
                        <label for="content">本文</label>
                        <textarea name="content">{{ old('content') }}</textarea>
                    </div>
                    <button type="submit">投稿</button>
                </form>
            </div>
        </article>
    </main>

    <footer>        
        <p>&copy; 投稿アプリ All rights reserved.</p>
    </footer>
</body>

</html>
```

### edit.blade.php:投稿編集画面

```php
`
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>投稿編集</title>    
</head>

<body>
    <header>
        <nav>
            <div>                
                <a href="{{ route('posts.index') }}">投稿アプリ</a>          
            </div>
        </nav>
    </header>

    <main>
        <article>
            <div>                
                <h1>投稿編集</h1>
                
                @if ($errors->any())
                    <div>
                        <ul>
                            @foreach ($errors->all() as $error)
                                <li>{{ $error }}</li>
                            @endforeach
                        </ul>
                    </div>
                @endif 
                
                <div>
                    <a href="{{ route('posts.index') }}">&lt; 戻る</a>                                  
                </div>
                
                <form action="{{ route('posts.update', $post) }}" method="post">
                    @csrf
                    @method('patch')
                    <div>
                        <label for="title">タイトル</label>
                        <input type="text" name="title" value="{{ $post->title }}">
                    </div>
                    <div>
                        <label for="content">本文</label>
                        <textarea name="content">{{ $post->content }}</textarea>
                    </div>
                    <button type="submit">更新</button>
                </form>
            </div>
        </article>
    </main>

    <footer>        
        <p>&copy; 投稿アプリ All rights reserved.</p>
    </footer>
</body>

</html>
```

### show.blade.php:詳細画面表示

```php
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>投稿詳細</title>
</head>

<body>
    <header>
        <nav>
            <div>                
                <a href="{{ route('posts.index') }}">投稿アプリ</a>          
            </div>
        </nav>
    </header>

    <main>
        <article>
            <div>                
                <h1>投稿詳細</h1>  

                @if (session('flash_message'))
                    <p>{{ session('flash_message') }}</p>
                 @endif

                <div>    
                    <a href="{{ route('posts.index') }}">&lt; 戻る</a>                              
                </div>

                <div>
                    <div>
                        <h2>{{ $post->title }}</h2>
                        <p>{{ $post->content }}</p>
                    </div>
                        <div>                            
                            <a href="{{ route('posts.edit', $post) }}">編集</a>
                            
                            <form action="{{ route('posts.destroy', $post) }}" method="post">
                                //↓クロスサイトリクエストフォージェリ対策
																@csrf
                                @method('delete')                                        
                                <button type="submit">削除</button>
                            </form>
                        
                        </div>
                </div>                 
            </div>
        </article>
    </main>

    <footer>        
        <p>&copy; 投稿アプリ All rights reserved.</p>
    </footer>
</body>

</html>
```

## コントローラ：MVCのC！VとMを制御するよ！

php artisan make:controller コントローラ名　で生成する。

コントローラ名は、やり取りするモデルに合わせて名前を変えるのが一般的。

今回は、postモデルとやり取りするので、Postcontrollerとする。

<strong>app/Http/Controllersフォルダの中にあるよ！

```php
`<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;

class PostController extends Controller {
    // 一覧ページ
    public function index() {        
        $posts = Post::latest()->get();
 
        return view('posts.index', compact('posts'));
   }
     // 作成ページ
    public function create() {
            return view('posts.create');
    }
     // 作成機能
     // 作成機能
     public function store(Request $request) {
        $request->validate([
            'title' => 'required',
            'content' => 'required',
        ]);
        
        $post = new Post();
        $post->title = $request->input('title');
        $post->content = $request->input('content');
        $post->save();

        return redirect()->route('posts.index')->with('flash_message', '投稿が完了しました。');
    }

      // 詳細ページ
      public function show(Post $post) {
        return view('posts.show', compact('post'));
    }

    //更新
    public function edit(Post $post) {
        return view('posts.edit', compact('post'));
    }

    // 更新機能
    public function update(Request $request, Post $post) {
        $post->title = $request->input('title');
        $post->content = $request->input('content');
        $post->save();

        return redirect()->route('posts.show', $post)->with('flash_message', '投稿を編集しました。');
    }

    // 削除機能
    public function destroy(Post $post) {
        $post->delete();

        return redirect()->route('posts.index')->with('flash_message', '投稿を削除しました。');
    }
    
}
```

## ルーティング：経路制御をするよ！

「このURLにアクセスしたときは○○コントローラの□□アクションを実行する」のように、ユーザーからのリクエストに応じてコントローラを選択する役割を担う。

<strong>routes\web.phpに記述するよ！

基本コードは

```php
`Route::HTTPリクエストメソッド名('URL', [コントローラ名::class, 'アクション名']);
//例えばPostコントローラのindexアクションであれば
Route::get('/posts', [PostController::class, 'index']);
```

設定する際に以下のようにname()メソッドを使うことで、そのルートに名前を付けられる

```php
`
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
```

ルートに名前を設定すると、bladeファイルにて、route()ヘルパーを使うことで簡易に呼び出すことができる。

```php
`<!-- 通常のリンク -->
<a href="/posts">投稿アプリ</a>

<!-- 名前付きルート -->
<a href="{{ route('posts.index') }}">投稿アプリ</a>
```

**また、use宣言でルーティングを設定するコントローラを宣言するを忘れないこと！**

```php
`// ルーティングを設定するコントローラを宣言する
 use App\Http\Controllers\PostController;
```

### ルーティングの中身

```php
`web.php
<?php

use Illuminate\Support\Facades\Route;
 // ルーティングを設定するコントローラを宣言する
use App\Http\Controllers\PostController;

Route::get('/', function () {
    return view('welcome');
});

/// 投稿の一覧ページ
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');

// 投稿の作成ページ
Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');

// 投稿の作成機能
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');

// 投稿の詳細ページ
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');

// 投稿の更新ページ
Route::get('/posts/{post}/edit', [PostController::class, 'edit'])->name('posts.edit');

// 投稿の更新機能
Route::patch('/posts/{post}', [PostController::class, 'update'])->name('posts.update');
// 投稿の削除機能
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->name('posts.destroy');
```

## モデルの作成：データベースとやりとりしてデータの作成、読み取り、更新、削除といった処理を行う

php artisan make:model モデル名というコマンドを打つと、

<strong>app/Models

のフォルダの中に生成されるよ。

モデル名は必ずテーブル名の単数形にすること。（今回：posts⇒post)

そうすると不思議機能でDBとやり取りしてくれる。

DBの数だけモデルがいるよ！

びっくりするくらい記述が少ないけどなぜか動くよ！

```php
`post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
}
```

一応これで最小構成のTodoアプリが作れるはず？

お好みで、BootStrapで成形してやってね！