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

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

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

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Q&A

解決済

1回答

2241閲覧

PHPで複数のタグを中間テーブルを利用してDBに登録する方法

退会済みユーザー

退会済みユーザー

総合スコア0

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

PDO

PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

PHP

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

0グッド

0クリップ

投稿2021/04/21 13:56

編集2021/04/22 13:17

前提・実現したいこと

PHPで複数のタグを中間テーブルを利用してDBに登録する方法が知りたいです。

現在自作のphpアプリを製作中です。

以下のように投稿フォームを作成しました。
イメージ説明
![イメージ説明

タグ以外のDB登録は実装できています。

複数選択できるタグを中間テーブルを用いてDBに登録する方法が知りたいです。

テーブルは以下のように設計しています。
投稿テーブル
イメージ説明

タグテーブル
イメージ説明

投稿とタグの中間テーブル
イメージ説明

今のイメージとしては、
投稿ボタンが押される

入力したタグはセレクトで取得する

3つのテーブルは外部結合する

投稿テーブルと中間テーブルにデータを追加

こんな流れなのかな?と思っています。

該当のソースコード

投稿フォーム(post.php)

php

1<a href="index.php">リスト一覧へ</a> 2<?php 3 4// 直リンクの禁止 5if (empty($_SERVER["HTTP_REFERER"])) { 6 header('Location: /'); 7 exit; 8} 9 10session_start(); 11require_once(ROOT_PATH .'/Models/Post.php'); 12require_once(ROOT_PATH .'function.php'); 13ini_set('display_errors', "On"); 14$obj = new Post(); 15 16$err = []; 17 18 if($_SERVER['REQUEST_METHOD'] === 'POST'){ 19 20 $title = filter_input(INPUT_POST, 'title'); 21 $text = filter_input(INPUT_POST, 'text'); 22 $tags = filter_input(INPUT_POST, 'tags'); 23 $category = filter_input(INPUT_POST, 'category'); 24 $price = filter_input(INPUT_POST, 'price'); 25 以下バリデーションは省略 26 27 // エラーがなければ、DBにデータを保存し、リスト一覧にページ遷移 28 if(count($err) === 0) { 29 $result = $obj->createList($_POST, $save_path); 30 $_SESSION['list_msg'] = "リストの投稿に成功しました!"; 31 header('Location: index.php'); 32 exit; 33 } 34 } 35?> 36 37<!DOCTYPE html> 38<html lang="en"> 39<head> 40 <meta charset="UTF-8"> 41 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 42 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 43 <script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.min.js"></script> 44 <script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.polyfills.min.js"></script> 45 <link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet" type="text/css" /> 46 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> 47 <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet"> 48 <link rel="stylesheet" href="/css/posts.css"> 49 <title>リスト投稿画面</title> 50</head> 51<body> 52<?php include(ROOT_PATH .'Views/common/header.php'); ?> 53 <div class="p-wrapper"> 54 <div class="p-container"> 55 <h2 id="p-title">リストを投稿する</h2> 56 <form action="" method="POST" enctype="multipart/form-data" id="p-form"> 57 <!-- タイトル --> 58 <div class="mb-3"> 59 <label for="kome"><font color="red">*</font></label> 60 <label for="title" class="form-label">タイトル</label> 61 <?php if(isset($err['title'])): ?> 62 <p class="err"><font color="red"><?php echo $err['title'] ?></font></p> 63 <?php endif; ?> 64 <input type="text" class="form-control" id="title" name="title" value="<?php if(isset($title)) echo h($title) ?>" placeholder="タイトルを入力してください(30文字以内)"> 65 </div> 66 <!-- タグ --> 67 <div class="tag-lebel"> 68 <label for="kome"><font color="red">*</font></label> 69 <label for="tag" class="form-label">タグ(最低1つは選択しましょう)</label> 70 <?php if(isset($err['tags'])): ?> 71 <p class="err"><font color="red"><?php echo $err['tags'] ?></font></p> 72 <?php endif; ?> 73 </div> 74 <div class="mb-3 tag-form"> 75 <input name="tags" class='tag_field' placeholder="+タグの候補を選択してください。(最大5つまで選択可能)" value='<?php if(isset($tags)) echo h($tags) ?>'> 76 </div> 77 <!-- サービス詳細 --> 78 <div class="mb-3"> 79 <label for="kome"><font color="red">*</font></label> 80 <label for="contents" class="form-label">詳細</label> 81 <?php if(isset($err['text'])): ?> 82 <p class="err"><font color="red"><?php echo $err['text'] ?></font></p> 83 <?php endif; ?> 84 <textarea class="form-control" id="contents" name="text" rows="20" placeholder="サービスの内容、利用者のメリット、アピールしたい実績などを3000文字以内で具体的に書いてください。具体的でわかりやすいほど、リストを見た企業がリクエストをしてくれる確率がアップします。"><?php if(isset($text)) echo h($text) ?></textarea> 85 </div> 86 <!-- カテゴリー --> 87 <h6 id="p-category"><label for="kome"><font color="red">*</font></label>カテゴリーを選択してください</h6> 88 <?php if(isset($err['category'])): ?> 89 <p class="err_one"><font color="red"><?php echo $err['category'] ?></font></p> 90 <?php endif; ?> 91 <select class="form-select" id="category-select" name="category"> 92 <?php if(isset($_POST['category'])): ?> 93 <option selected><?php echo $obj->setCategoryName($category); ?></option> 94 <?php else: ?> 95 <option selected value="0">カテゴリーを選択してください</option> 96 <?php endif; ?> 97 <option value="1">求人</option> 98 <option value="2">人材育成・研修</option> 99 <option value="3">集客・マーケティング</option> 100 <option value="4">Webサイト制作</option> 101 <option value="5">Webコンテンツ制作</option> 102 <option value="6">イラスト</option> 103 <option value="7">営業・コールセンター代行</option> 104 <option value="8">ビジネス相談・経営コンサル</option> 105 <option value="9">士業(税理士・行政書士など)</option> 106 <option value="10">翻訳・語学</option> 107 <option value="11">クリーニング</option> 108 <option value="12">音楽・ナレーション</option> 109 <option value="13">その他</option> 110 </select> 111 <!-- サービスの参考価格 --> 112 <h6 id="p-price"><label for="kome"><font color="red">*</font></label>サービスを利用する際の参考価格</h6> 113 <?php if(isset($err['price'])): ?> 114 <p class="err_one"><font color="red"><?php echo $err['price'] ?></font></p> 115 <?php endif; ?> 116 <div class="mb-3"> 117 <input type="text" class="form-control" id="p-price_form" name="price" placeholder="29800" value="<?php if(isset($price)) echo h($price) ?>"> 118 </div> 119 <!-- 画像 --> 120 <h6 id="p-image">画像を追加してください</h6> 121 <?php if(isset($err['img'])): ?> 122 <p class="err_one"><font color="red"><?php echo $err['img'] ?></font></p> 123 <?php endif; ?> 124 <input type="hidden" name="MAX_FILE_SIZE" value="1048576"> 125 <input type="file" class="form-control" id="p-image_upload" name="img" value="<?php if(isset($_FILES['img']['name'])) echo $_FILES['img']['name'] ?>"> 126 <!-- リスト投稿ボタン --> 127 <div class="p-btn"> 128 <button type="submit" class="btn btn-primary" id="p-btn_btn" name="b">リストを投稿する</button> 129 </div> 130 </form> 131 </div> 132 </div> 133 <?php include(ROOT_PATH .'Views/common/footer.php'); ?> 134<script type="text/javascript" src="/js/script.js"></script> 135</body> 136</html>

tagのjavascript(script.js)

var input = document.querySelector('input[name="tags"]'), // init Tagify script on the above inputs tagify = new Tagify(input, { whitelist: ["急募","アフターフォロー","低価格","要相談"], maxTags: 5, dropdown: { maxItems: 50, // <- mixumum allowed rendered suggestions classname: "tags-look", // <- custom classname for this dropdown, so it could be targeted enabled: 0, // <- show suggestions on focus closeOnSelect: false // <- do not hide the suggestions dropdown once an item has been selected } }); // "remove all tags" button event listener document.querySelector('.tags--removeAllBtn') .addEventListener('click', tagify.removeAllTags.bind(tagify)) // Chainable event listeners tagify.on('add', onAddTag) .on('remove', onRemoveTag) .on('invalid', onInvalidTag); // tag added callback function onAddTag(e){ console.log(e, e.detail); console.log( tagify.DOM.originalInput.value ) tagify.off('add', onAddTag) // exmaple of removing a custom Tagify event } // tag remvoed callback function onRemoveTag(e){ console.log(e, e.detail); } // invalid tag added callback function onInvalidTag(e){ console.log(e, e.detail); }

投稿をDBに登録するロジック(Post.php)

<?php require_once(ROOT_PATH .'/Models/Db.php'); ini_set('display_errors', "On"); class Post { /** * リストの投稿をDBに保存 * @param string $postDate * @param string $save_path * @return bool $result */ public function createList($postDate, $save_path) { $result = false; $sql = 'INSERT INTO posts (title, text, category_id, price, img) VALUES (:title, :text, :category_id, :price, :img)'; $title = $postDate['title']; $text = $postDate['text']; $category = $postDate['category']; $price = $postDate['price']; try { $stmt = connect()->prepare($sql); $stmt->bindValue(':title', $title, PDO::PARAM_STR); $stmt->bindValue(':text', $text, PDO::PARAM_STR); $stmt->bindValue(':category_id', (int)$category, PDO::PARAM_INT); $stmt->bindValue(':price', (int)$price, PDO::PARAM_INT); $stmt->bindValue(':img', $save_path, PDO::PARAM_STR); $result = $stmt->execute(); return $result; } catch(\Exception $e) { return $result; } }

試したこと

中間テーブルのやり方とは別に投稿のDBにtagを追加し、中間テーブル使わずに強引にやってみた。

$sql = 'INSERT INTO posts (title, text, category_id, price, img,tag) VALUES (:title, :text, :category_id, :price, :img, :tag)'; ... $stmt->bindValue(':tag', $tag, PDO::PARAM_STR); ...

イメージ説明
このように複数のタグはDBに保存できたが、何やらvalueがついていた。

こういった強引なやり方ではなく中間テーブルを持ちたやり方はどのようにすればいいのでしょうか?
サンプルコードとかあったら嬉しいです。

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

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

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

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

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

yambejp

2021/04/22 00:19

肥大化して理解を超えているならもっとシンプルなモデルをつかって テストすることです
退会済みユーザー

退会済みユーザー

2021/04/22 13:57 編集

承知いたしました。
guest

回答1

0

ベストアンサー

投稿ボタンが押される

入力したタグはセレクトで取得する

3つのテーブルは外部結合する

投稿テーブルと中間テーブルにデータを追加

色々と誤解しているようなので、
まずはSQLだけで中間テーブルを使ったリレーションの構築を行ってみるのが良いかと思いますよ。

特に、中間テーブルが存在しない状態で

3つのテーブルは外部結合する

を行う事は不可能なので、まずは投稿とタグを作成してから中間テーブルにその関連を投入しましょう。

最も単純なケースだと

  1. タグのIDを用意する
  2. 投稿のIDを用意する
  3. 中間テーブルにタグのIDと投稿のIDをINSERTする

です。

phpMyAdminの機能で

  1. 投稿をINSERTする
  2. タグをINSERTする
  3. それぞれのレコードのIDをメモしておいて、中間テーブルに関連データをINSERTする

としてみるとやらなければいけないことが理解できると思います。


これをアプリケーションで実装する場合、

  1. POST内容から投稿をINSERTして、そのIDを取得する。PDO::lastInsertIdを使うと楽
  2. 同じくPOST内容からタグをその数だけINSERTし、タグIDの一覧を取得する
  3. タグIDの一覧をforeachなりして、投稿IDとタグIDの関連テーブルにデータをINSERTする

という感じになります。

投稿2021/04/21 14:48

編集2021/04/21 14:51
tanat

総合スコア18713

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

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

退会済みユーザー

退会済みユーザー

2021/04/22 11:57

ご回答ありがとうございます。 今まで登録とか更新とか単調な内容だったので、中間テーブルは一気に難易度上がりますね。 もう少し調べて実装してみます。
退会済みユーザー

退会済みユーザー

2021/04/22 13:52

2の処理がわからないのですが、POSTするテーブルにtagカラムを追加した方がいいのでしょうか?
tanat

2021/04/22 13:58

うーん、まずは回答前半のphpMyAdminで狙いのレコードをインサートすること試してみてください。 PHPはそれを自動化するための手段なので、元々やりたい処理を正確に理解する必要があります
退会済みユーザー

退会済みユーザー

2021/04/22 14:19

ありがとうございます。 流れは理解できました。 tanatさまがすでに記述されているように、 ①投稿したIDをlastInsertIdで取得 ②tagテーブルの一覧を取得し、foreachで選択したタグを取得 ③lastInsertIdと複数のタグを中間テーブルにそれぞれINSERTする POSTされた複数のタグをどうやって取得するかまだ考え中ですが、なんとか頑張って実装してみます。
tanat

2021/04/22 17:27

> POSTされた複数のタグをどうやって取得するかまだ考え中ですが タグ名は分かってるわけですから、SELECTでタグテーブルからタグ名を指定して取得すればOKです
退会済みユーザー

退会済みユーザー

2021/04/23 10:55

ありがとうございます。 以下のようにタグ取得についてコード書いてみました。 // タグの取得 public function GetByTagsName($tags) { $sql = 'SELECT * FROM tag WHERE name = :name'; $stmt = connect()->prepare($sql); $stmt->bindValue(':name', $tags, PDO::PARAM_STR); $stmt->execute(); foreach($stmt as $row) { echo $row['name']; } $result = $stmt->fetchAll(PDO::FETCH_ASSOC); return $result; } しかし、var_dumpでarray(0){}と空で返って来ちゃいます。 このような場合、なんで空で返ってくるのでしょうか?
tanat

2021/04/23 11:08

$tagsに狙い通りの値が入って無いから?(配列で渡してる?) まずは固定値で試してみてはいかがでしょうか。 あとは、MySQL側で全クエリのログを出力するようにして、実際に実行されているSQLを確認するのも良いです。
退会済みユーザー

退会済みユーザー

2021/04/23 11:20

わかりました!隅々までデバッグしてみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問