Blogブログ

laravel

2022.03.26

laravelでカテゴリーのCRUDとブログ投稿を様々な鮨と共に提供しましょう

前回の続きです。

前回のadminのCRUDの要領で作ればすぐできますので、
商品カテゴリーの親子関係を作りながら今回は画像のアップロードなんかを折り混ぜながら解説していこうと思います。

まずはroutingからやっていきます。

前回やったようにresourceを使っていきますので、
web.phpに
$router->resource(‘categories’, ‘CategoriesController’);
を記載します。

Route::group(['prefix' => 'admin', 'namespace' => 'Admin', 'as' => 'admin.'], function($router) {
    $router->get('login', 'Auth\LoginController@showLoginForm')->name('login');
    $router->post('login', 'Auth\LoginController@login')->name('dologin');
    $router->get('/auth/logout', 'Auth\LoginController@logout')->name('logout');
    $router->resource('accounts', 'AccountsController');
    //カテゴリーのルーティング
    $router->resource('categories', 'CategoriesController');
});

これで、admin配下にcategories系のCRUDに関数ルーティングアクションを予期することができます。

    public function index()
    {
    }

    public function create()
    {
    }

    public function store(Request $request)
    {
    }
    public function edit($id)
    {
    }
    public function update(Request $request, $id)
    {
    }
    public function show($id)
    {
    }
    public function destroy($id)
    {
    }

これのroutingができたってことですね。

南青山の鮨あき

次にコントローラーを書いてみます。

<?php
namespace App\Http\Controllers\Admin;

use App\Http\Request\Admin\Category\CreateEditRequest;
use App\Models\Category;
use Illuminate\Http\Request;

class CategoriesController extends AdminBaseController
{
    public function index(Request $request)
    {
        $list = Category::orderBy('created_at', 'desc')->paginate(10);
        return $this->view('index', compact('list', 'request'));
    }

    public function create()
    {
        $data = new Category();
        return view('admin.categories.create', compact('data'));
    }

    public function store(CreateOrEditRequest $request)
    {
        $category = new Category();
        $category->fill($request->all());

        // 画像アップロード
        if ($request->file('img')) {
            //アップロードしたあとの返り値は画像pathです。
            $category->img = $request->file('img')->store('uploads/category');
        }

        if ($category->save()) {
            return redirect(route('admin.categories.index'));
        }

        return back()->withInput();
    }

    public function edit($id)
    {
        $data = Category::findOrFail($id);
        if (empty($data)) {
            return redirect(route('admin.categories.index'));
        }
        return view('admin.categories.edit', compact('data'));
    }

    public function update(CreateEditRequest $request, $id)
    {
        $category = Category::findOrFail($id);

        $category->fill($request->all());
         // 画像アップロード
         if ($request->file('img')) {
             $category->img = $request->file('img')->store('uploads/category');
         }
        if ($category->save()) {
            return redirect(route('admin.categories.index'));
        }

        return back()->withInput();
    }

    public function show($id)
    {
        $data = Category::findOrFail($id);
        return view('admin.categories.show', compact('data'));
    }

    public function destory(Request $request)
    {
        $id = $request->post('id');
        $category = Category::findOrFail($id);
        $category->delete();
        return redirect('admin.categories.index');
    }
}

画像アップの部分は、
$category->img = $request->file(‘img)->store(‘uploads/category’);
となっていますが、
html側のname属性のimgのファイルを
storage/appの配下にuploads/categoryディレクトリを作りそこにアップしてくれます。※自分でフォルダを作る必要があるので作りましょう。


migrationは、
php artisan make:migration create_categories_table –create=categories
を実行し、
upの中に

    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('img')->nullable();
            $table->timestamps();
        });
    }

と書きます。
画像のpathの保存とカテゴリー名を予期しました。

先にテーブルを作っておきます。
docker psでコンテナIDを把握し、例えばXXXXXXだとしたら、
docker exec -it XXXXXX /bin/bashでコンテナにログインし
php artisan migrate
をしてテーブルを作成します。

Modelsを作っていきます。

<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    protected $fillable = ['name', 'img'];
}

鮨mです。

では、バリデーションのRequestを作っていきます。

<?php

namespace App\Http\Request\Admin\Category;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;

class CreateEditRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        $rules = [];
        $rules['name'] = 'required';
        if (request()->has('id')) {
            $rules['img'] = 'image|max:5120';
        } else {
            $rules['img'] = 'required|image|max:5120';
        }
        return $rules;
    }

    public function attributes()
    {
        return [
            'name' => 'カテゴリー名',
            'img' => '画像'
        ];
    }

    protected function failedValidation(Validator $validator)
    {
        throw (new HttpResponseException(response()->json([
            'code' => 422,
            'status' => 'FAIL',
            'message' => $validator->errors(),
        ], 200)));
    }
}

滋賀県の京極寿司

ではviewを作っていきます。

今回は..こんな感じのコードにしてみます。

@extends('admin.layouts.default')

@section('content')
  <div id="container">
    <div id="main">
      <h1 id="page_title">カテゴリーを作成する</h1>
      <div id="main_contents">
        <div id="main">
          <form action="{{route('admin.categories.store')}}" method="post"class="form-horizontal" enctype="multipart/form-data" id="form_data">
          @csrf
            <fieldset>
              <div class="form-group">
                <label class="col-md-4 control-label">カテゴリー名 <span>必須</span></label>
                <div class="col-md-4">
                  <input name="name" value="{{ old('name', $data->name) }}" type="text" placeholder="" class="form-control input-md" required="" />
                  <div hidden id="name_error" name="error_div" style="color: red; margin-top: 10px;"></div>
                </div>
              </div>
              <div class="form-group">
                <label class="control-label" for="filebutton">
                画像<br>
                <span class="image-notification">
                ※最大サイズ: 5MB以内<br>
                ※推奨画像比率: 16×9
                </span>
                </label>
                <div class="col-md-4">
                   <input id="avatar_input" name="img" class="input-file" type="file" accept="image/gif,image/jpeg,image/jpg,image/png,image/svg" />
                </div>
              </div>
              <div class="form-group">
                <div class="col-md-4">
                  <button type="button" onclick="window.location.href='{{ route('admin.categories.index') }}'" class="back_btn">戻る</button>
                  <button type="submit" class="back_btn">登録</button>

                </div>
              </div>
            </fieldset>
          </form>
        </div>
      </div>
    </div>
  </div>
@endsection

enctype=”multipart/form-data” をformに入れるのを忘れないように。

そうすると。

できましたね。

postしてみると・・・

ではカテゴリーの登録だけしてみましょう。
画像がアップロードされてDBに画像名とpath値が入っていればOKですね。

では、一覧や詳細は今回はおいておいて、次ブログいきます。

恵比寿の鮨結う です。

同じようにBlog投稿も作ってみます。

model Controller Requestはそれぞれこんな感じにしてみます。

ここから、
Blogを獲得にカテゴリーを複数選べるようにしてみましょう

まず、登録画面に、
category一覧を選択させるようなチェックボックスを表示するために、
Blogsコントローラーでカテゴリー一覧を持ってきます。

そうすると

このデータを保存するために
category_blog_relationテーブルを作成し、
ブログの値に加えて、リレーションテーブルに選択されたカテゴリーも
登録していきます。

    public function up()
    {
        Schema::create('blog_category_relations', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('blog_id')->unsigned();
            $table->bigInteger('category_id')->unsigned();
            $table->timestamps();
            //外部キー制約
            $table->foreign('blog_id')
                    ->references('id')
                    ->on('blogs');

            $table->foreign('category_id')
                    ->references('id')
                    ->on('categories');
        });

    }

外部キーをつけるときはbigIntegerにすることと、unsignedを忘れないようにしてください。そうしないと作られませんよ。

では、modelで、Blog_category_relationクラスを作ります。

中身は、何も書かなくていいです。

<?php
                               
namespace App\Models;          
use Illuminate\Database\Eloquent\Model;
  
class Blog_category_relation extends Model
{
} 

ブログのモデルは、ちょっと注意してください

<?php
                               
namespace App\Models;          
use Illuminate\Database\Eloquent\Model;

class Blog extends Model       
{ 
    protected $fillable = ['title', 'img','editor'];
  
    public function categories()    
    { 
                                  //↓クラス名                     //↓テーブル名
      return $this->belongsToMany(Blog_category_relation::class, 'blog_category_relaitons');
    }   
}     

ブログテーブルが、
カテゴリーとn:nのときはこのように
belogsToManyを記載します。

念のため、
対象テーブルから見て、1:nなのか、n:1なのかn:nなのかによっての関数を書いておきますのでメモに使ってください

    public function example_1_n()
    {
        return $this->hasMany(子のクラス名::class);
    }

    public function example_n_n()
    {
        return $this->belongsToMany(今回のようなn対nのクラス名::class, 'job_hope_middles');
    }

    public function example_n_1()
    {
        return $this->belongsTo(親のクラス名::class);
    }

麻布 鮨よしかわ

では、Blogのstoreを作ります。

       public function store(CreateOrEditRequest $request)
    {
        $blog = new Blog();
        $blog->fill($request->all());
        $blog->editor ="";
        // 画像アップロード
        if ($request->file('img')) {
            //アップロードしたあとの返り値は画像pathです。
            $blog->img = $request->file('img')->store('uploads/blog');
        }

        if ($blog->save()) {
            //ブログが保存されたらrelationの保存をします。
            //syncが入ってきたidを見て、もしもともと選択されていたものが消えてるならrelationテーブルの値も消してくれるし、
            //必要な値だけを登録してくれます。
            $res = $blog->categories()->sync($request->get('category'));
            if($res)
            {
                return redirect(route('admin.blogs.index'));
            }
        }

        return back()->withInput();
    }

しっかりリレーションを書いていれば、
すごく便利ですね。

では、ブログを登録してみましょう

登録できました。

これで、n:nのリレーションを持つブログ(画像アップロード含む)を登録することができましたね。

照寿司

寿司栄

お疲れ様でした。