質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

1回答

1577閲覧

bookテーブルと多対多の関係のtagテーブルの追加登録の実装がうまくいきません!

aoinosuke

総合スコア8

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2020/08/13 12:43

tagテーブルに新規追加で登録できるようにしたいです。
最初にbookテーブルと一緒に登録できるのですが、追加コマンドから新しくデータを挿入するときに過去のタグ名前が上書きされてしまいます。
原因はforeachで囲ってないために最後のデータを上書きしてしまうことはわかっているのですが、ここからの実装ができずにいます。

$data["book_id"]でデバックするとその指定のbook_idが一覧で取れます。
array_search array_coulmnで一致させればと思っております。

ですがどうしてもできなかったので質問させていただきます。
よろしくお願いします。

tag controller public function store(Request $request,Book $book, Tag $tag) { $user = auth()->user(); $data = $request->all(); $books = $book->all(); //ここを実装したいです。 foreach($books as $book) $book_ids = $book->id; var_dump($book_ids); #カテゴリ名の重複登録を防ぐ $storedTagNames = $tag->whereIn('name',$data["tags"])->pluck('name'); $newTagNames = array_diff($data["tags"],$storedTagNames->all()); //タグ挿入 $tag->tagStore($newTagNames); //$tagテーブルに挿入した値の名前からidを取得し中間テーブルへ $tag_ids = $tag->getTagIds($data["tags"]); //中間テーブルにidを設置 $book->bookTagSync($tag_ids); return redirect()->route('books.show', $book['id']); }
book model public function bookTagSync(Array $tag_ids){ //syncメソッドは中間テーブルに設置しておくIDの配列を渡す。https://yshrfmru.hatenablog.com/entry/2019/03/24/131219 $this->tags()->sync($tag_ids); }
tag model public function tagStore(Array $_tag_names){ //タグがすでにあるかの判定 if(!empty($_tag_names)){ //タグがあるかforeachで探す.['name' => $tag_name] foreach($_tag_names as $tag_name){ $tag_names[] = ['name' => $tag_name]; } //insertOrIgnoreであれば無視、なければ挿入 DB::table('tags') ->insertOrIgnore($tag_names); } } public function getTagIds($tag_names){ foreach($tag_names as $tag_name){ //idから名前を1から取り出して$tag_idに代入 $tag_id = $this::select('id')->where("name",$tag_name)->first(); //$tag_idのidを配列$tag_ids[]に全て代入 $tag_ids[] = $tag_id->id; } return $tag_ids; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

phper.k

2020/08/14 01:31

いったい、何を参考にコードを書いていますか? Laravelの普通の使い方をしていないように見受けられます。
aoinosuke

2020/08/14 05:43

参考にしているものは特になく、完全に独学でやっております。 なので普通の使い方を出来てないところは実力不足です。 申し訳ありません。
phper.k

2020/08/14 05:51 編集

現状のソースはほとんど破棄することになりますが、それでも良ければ回答しますが如何しましょうか?
aoinosuke

2020/08/14 05:53

はい! 是非お願いします!
phper.k

2020/08/14 06:02

使っているLaravelのバージョン、Databaseの種類とバージョンを記載してください。
aoinosuke

2020/08/14 06:13

Laravel Framework 7.19.1 Mysql: 5.7.29 以上になります。 よろしくお願いします。
guest

回答1

0

php

1// routes/web.php 2 3Route::resource('/books', 'BookController'); 4Route::resource('/tags', 'TagController');

モデルその他を一緒に作成

-a オプションをして、migration, controller, factory, Seeder を一度に作成する

php artisan make:model Book -a
php artisan make:model Tag -a

中間テーブルを作成

php artisan make:migration create_book_tag_table

※テーブル名は結合するモデルの単数形でアルファベット順

class CreateBookTagTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('book_tag', function (Blueprint $table) { $table->unsignedBigInteger('book_id'); $table->unsignedBigInteger('tag_id'); $table->unique(['book_id', 'tag_id']); }); } }

Bookモデルにリレーションを定義する

php

1 2class Book extends Model 3{ 4 /** 5 * @return BelongsToMany 6 */ 7 public function tags(): BelongsToMany 8 { 9 return $this->belongsToMany(Tag::class); 10 } 11}

Tagモデルにリレーションを定義する

php

1 2class Tag extends Model 3{ 4 /** 5 * @return BelongsToMany 6 */ 7 public function books(): BelongsToMany 8 { 9 return $this->belongsToMany(Book::class); 10 } 11}

BookController 実装

namespace App\Http\Controllers; use App\Book; use App\Tag; use Illuminate\Http\Request; use phpDocumentor\Reflection\DocBlock\Tag; use Symfony\Component\HttpFoundation\RedirectResponse; class BookController extends Controller { /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return RedirectResponse */ public function store(Request $request): RedirectResponse { // Tag名に存在するレコードがあればそのまま、なければ作成 $tag = Tag::firstOrCreate([ 'name' => $request->tag_name ]); // Bookを作成 $book = new Book(); $book->fill( $request->all() )->save(); // タグを関連づける $book->tags() ->attach($tag->id); return redirect()->route('books.show', compact('book')); }

大まかにはこんな感じです

https://readouble.com/laravel/7.x/ja/eloquent-relationships.html#many-to-many

投稿2020/08/14 06:26

phper.k

総合スコア3923

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aoinosuke

2020/08/14 06:36

insertOrIgnoreではなくfirstOrCreateの方が使い勝手はいいのでしょうか? 何はともあれ、お時間割いて丁寧に教えていただきありがとうございます! 是非参考にして実装を進めます。
phper.k

2020/08/14 06:38 編集

insertOrIgnoreでは目的を果たせません。 まずは、動かしてみましょう。 fillable とかは適宜補ってね。
aoinosuke

2020/08/14 06:45

承知しました!色々調べていきます! 重ね重ねありがとうございます!
aoinosuke

2020/08/14 14:46

今気づいたのですがこれtagscontrollerで実装してかったのです。。
phper.k

2020/08/14 14:57

やり方は一緒だし、マニュアル見て頑張ってみてください。 試行錯誤の経験が身になりますから。
aoinosuke

2020/08/14 23:10

了解です。 やってみます。
aoinosuke

2020/09/03 08:24

なかなかうまくいきません。 $tags = $request->tags $tags =[]; foreach($tags as $tag ){ } 例えば上でforeachを掛けると先頭しか取り出せなくなってしまいます。 なのでこのまま実装しても先頭のタグしか中間テーブルに入らなくなっております。 tagsテーブルには全部の投稿は挿入できてます。
phper.k

2020/09/03 08:32

ごめんなさい。何言ってるかわからないです。
aoinosuke

2020/09/03 08:54

すみません。結局array_filter使って複数登録できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問