#使用するファイル
・User.php
・ProductController.php
・index.blade.php
・LikeComponent.vue
・app.js
・LikeController.php
#Userモデルにて多対多のリレーションを行う。
public function likeProducts()
{
return $this->belongsToMany(Product::class, 'like_products');
}
多対多のリレーションを行う。
belongsToManyの第一引数にリレーション先モデル名、第二引数に中間テーブル名を指定している。
#ProductControllerからindex.blade.phpに商品データを送る
public function index(ProductSearchService $productSearchService, Request $request)
{
$likeProducts = Auth::user()->likeProducts()->pluck('product_id');
$products = $productSearchService($request);
return view('products.index', compact([
'products',
'likeProducts',
]));
}
Auth::user()->likeProducts()->pluck('product_id');
先ほど多対多のリレーションを行なったのでそれを使用する。
中間テーブルであるlike_productsにログインユーザーが登録したproduct_idをコレクションで取得している。
#viewを用意(ここにlike-component)を埋め込む
<div class="row pt-2 px-5">
@foreach ($products as $product)
<a href="{{ route('products.show', $product->id) }}" class="mb-5 ml-5">
<img src="{{ asset('storage/product_images/'.$product->image_path_one) }}" style="width: 100px; height: 100px;"
class="img-thumbnail mx-auto d-block">
<div class="center-block">
<p class="text-center">{{ $product->name }}</p>
<p class="text-center">¥{{ number_format($product->price) }}</p>
</div>
</a>
<div id="app">
<like-component :product-id="{{ $product->id }}" :liked-data="{{ $likeProducts }}"></like-component>
</div>
@endforeach
</div>
foreachでコントローラーから送られてきた商品データのコレクションを一つずつ展開している。
like-componentへv-bindで展開したproductIdとログインユーザーがlike_productsテーブルに格納しているproductIdを渡している。
v-bindでの変数はケバブケースでないといけない。
<template>
<div>
<i
v-on:click="storeOrDelete"
:class="[isActiveTrue === true ? 'far fa-heart ml-3' : 'fas fa-heart ml-3']"
></i>
</div>
</template>
<script>
export default {
props: ["productId", "likedData"],
data() {
return {
isActiveTrue: this.likedData.includes(this.productId) ? false : true
};
},
methods: {
change() {
this.isActiveTrue = !this.isActiveTrue;
},
storeProductId() {
axios
.post("like/" + this.productId, {
productId: this.productId
})
.then(response => {
console.log("success");
})
.catch(err => {
console.log("error");
});
},
deleteProductId() {
axios
.delete("like/" + this.productId, {
data: {
productId: this.productId
}
})
.then(response => {
console.log("success");
})
.catch(err => {
console.log("error");
});
},
storeOrDelete() {
const isTrue = this.likedData.includes(this.productId);
if (isTrue === true) {
this.deleteProductId();
this.change();
} else {
this.storeProductId();
this.change();
}
}
}
};
</script>
propsで先ほどindex.blade.phpから渡されたproduct-idとliked-dataを受け取っている。
先ほど渡す時はケバブケースだったが、こちらではローワーキャメルケースで書かないといけない。
storeOrDeleteメソッドの説明をする。
const isTrue = this.likedData.includes(this.productId);
likeData(ユーザーがお気にいりしているproductIdが配列で格納されている)の中にその商品のIDがあるかincludesメソッドで調べている。もし、ある商品(お気にりしているということ)ならお気に入りから外し、なければお気に入り登録する。
changeメソッドでstyleの切り替えを行なっている。
:class="[isActiveTrue === true ? 'far fa-heart ml-3' : 'fas fa-heart ml-3']"
はisActiveTrueがtrueかfalseでスタイルの切り替えをおこなっている。
#作成したコンポーネントを使用できるようにする
Vue.component('like-component', require('./components/LikeComponent.vue').default);
new Vue({
el: '#app',
});
Vue.component('like-component', require('./components/LikeComponent.vue').default);
で先ほど作成したlike-componentを読み込んでいる。
new Vue({ el: '#app', });
でindex.blade.phpの#app内でvue.jsが使えるようになる。
#like-componentから非同期で送られてきたproductIdをlike_productsテーブルに登録・削除を行う。
public function store(Product $product)
{
Auth::user()->likeProducts()->attach($product);
}
public function delete(Product $product)
{
Auth::user()->likeProducts()->detach($product);
}
}
storeメソッドでは、like_productsテーブルにログインしているユーザーのIDとメソッドインジェクションの$product(like-componentから非同期で送られてきたproductId)をインサートしている。deletメソッドでは、反対に削除している。
これでお気に入り機能が完成した。