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

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

ただいまの
回答率

88.10%

PHP 登録状況で変わる選択肢の状態にあわせてforeach?などで書き出したい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,479

score 77

たびたびお世話になっています。
アンケートに関するPHPのページを作成しようと思っています。

1.行いたいことは、アンケートの本文と、選択枝のMySQLへの格納。
2.アンケート画面で、データベースから抽出して、選択肢を表示
3.チェックボックスやラジオボタンの状態を、DBへ書き込み

この中の2をどのようにできるかによって1の画面を作りたいと思っています。

下記のような配列のテスト画面を作りました。

//test.php
<?php
$survey= array(
    "sur1"=> array("紹介",
                   "看板",
                   "チラシ",

                   "フリーペーパー" => array ("雑誌A",
                                        "雑誌B",
                                         "雑誌C",
                                         "雑誌D"),

                   "ネット" => array ("ホームページ",
                                     "EPARK",
                                     "エキテン",
                                     "LINE",
                                     "Facebook",
                                     "Instagram",
                                     "その他")
                   ),

     "sur2"=> array("A市","B市","D市","E郡","その他のA県内","B県","その他の県"),
     "sur3"=> array("車で5分以内","車で10分以内","車で20分以内","車で30分以内","それ以上")

);


var_dump($survey);  

print '<br><br><br>';

var_dump($survey['sur1']);    

print '<br><br><br>'; 

var_dump($survey['sur1']['フリーペーパー']);

print '<br><br><br>';


//試してみてうまくいかなかったコードです。
//このようにすれば、フリーペーパーの中身は表示されますが、sur1やフリーペーパーをあらかじめ入力するのではなく、変数で入れたいのですが、その変数の取得方法が分かりませんでした。
foreach( $survey['sur1']['フリーペーパー'] as $value ){
  echo $value."<br>"; 
}


?>    

上記のPHPに対してブラウザに表示された内容のコピペです。


array(3) { ["sur1"]=> array(5) { [0]=> string(6) "紹介" [1]=> string(6) "看板" [2]=> string(9) "チラシ" ["フリーペーパー"]=> array(4) { [0]=> string(7) "雑誌A" [1]=> string(7) "雑誌B" [2]=> string(7) "雑誌C" [3]=> string(7) "雑誌D" } ["ネット"]=> array(7) { [0]=> string(18) "ホームページ" [1]=> string(5) "EPARK" [2]=> string(12) "エキテン" [3]=> string(4) "LINE" [4]=> string(8) "Facebook" [5]=> string(9) "Instagram" [6]=> string(9) "その他" } } ["sur2"]=> array(7) { [0]=> string(4) "A市" [1]=> string(4) "B市" [2]=> string(4) "D市" [3]=> string(4) "E郡" [4]=> string(19) "その他のA県内" [5]=> string(4) "B県" [6]=> string(15) "その他の県" } ["sur3"]=> array(5) { [0]=> string(16) "車で5分以内" [1]=> string(17) "車で10分以内" [2]=> string(17) "車で20分以内" [3]=> string(17) "車で30分以内" [4]=> string(12) "それ以上" } } 


array(5) { [0]=> string(6) "紹介" [1]=> string(6) "看板" [2]=> string(9) "チラシ" ["フリーペーパー"]=> array(4) { [0]=> string(7) "雑誌A" [1]=> string(7) "雑誌B" [2]=> string(7) "雑誌C" [3]=> string(7) "雑誌D" } ["ネット"]=> array(7) { [0]=> string(18) "ホームページ" [1]=> string(5) "EPARK" [2]=> string(12) "エキテン" [3]=> string(4) "LINE" [4]=> string(8) "Facebook" [5]=> string(9) "Instagram" [6]=> string(9) "その他" } } 


array(4) { [0]=> string(7) "雑誌A" [1]=> string(7) "雑誌B" [2]=> string(7) "雑誌C" [3]=> string(7) "雑誌D" } 

雑誌A
雑誌B
雑誌C
雑誌D

ブラウザのソースのコピペです。

array(3) {
  ["sur1"]=>
  array(5) {
    [0]=>
    string(6) "紹介"
    [1]=>
    string(6) "看板"
    [2]=>
    string(9) "チラシ"
    ["フリーペーパー"]=>
    array(4) {
      [0]=>
      string(7) "雑誌A"
      [1]=>
      string(7) "雑誌B"
      [2]=>
      string(7) "雑誌C"
      [3]=>
      string(7) "雑誌D"
    }
    ["ネット"]=>
    array(7) {
      [0]=>
      string(18) "ホームページ"
      [1]=>
      string(5) "EPARK"
      [2]=>
      string(12) "エキテン"
      [3]=>
      string(4) "LINE"
      [4]=>
      string(8) "Facebook"
      [5]=>
      string(9) "Instagram"
      [6]=>
      string(9) "その他"
    }
  }
  ["sur2"]=>
  array(7) {
    [0]=>
    string(4) "A市"
    [1]=>
    string(4) "B市"
    [2]=>
    string(4) "D市"
    [3]=>
    string(4) "E郡"
    [4]=>
    string(19) "その他のA県内"
    [5]=>
    string(4) "B県"
    [6]=>
    string(15) "その他の県"
  }
  ["sur3"]=>
  array(5) {
    [0]=>
    string(16) "車で5分以内"
    [1]=>
    string(17) "車で10分以内"
    [2]=>
    string(17) "車で20分以内"
    [3]=>
    string(17) "車で30分以内"
    [4]=>
    string(12) "それ以上"
  }
}
<br><br><br>array(5) {
  [0]=>
  string(6) "紹介"
  [1]=>
  string(6) "看板"
  [2]=>
  string(9) "チラシ"
  ["フリーペーパー"]=>
  array(4) {
    [0]=>
    string(7) "雑誌A"
    [1]=>
    string(7) "雑誌B"
    [2]=>
    string(7) "雑誌C"
    [3]=>
    string(7) "雑誌D"
  }
  ["ネット"]=>
  array(7) {
    [0]=>
    string(18) "ホームページ"
    [1]=>
    string(5) "EPARK"
    [2]=>
    string(12) "エキテン"
    [3]=>
    string(4) "LINE"
    [4]=>
    string(8) "Facebook"
    [5]=>
    string(9) "Instagram"
    [6]=>
    string(9) "その他"
  }
}
<br><br><br>array(4) {
  [0]=>
  string(7) "雑誌A"
  [1]=>
  string(7) "雑誌B"
  [2]=>
  string(7) "雑誌C"
  [3]=>
  string(7) "雑誌D"
}
<br><br><br><br><br><br>雑誌A<br>雑誌B<br>雑誌C<br>雑誌D<br>      

上記を元に、ブラウザに下記のように出力したいと思っていますが、上記のような配列をもとに、選択肢の数だけ出力するのは可能でしょうか?


アンケート
ここにアンケート本文

〇紹介 〇看板 〇チラシ フリーペーパー【 〇雑誌A 〇雑誌B 〇雑誌C 〇雑誌D 】 ネット 【 〇ホームページ 〇EPARK 〇エキテン 〇LINE 〇Facebook 〇Instagram 〇その他 】

ここにアンケート本文
〇A市 〇B市 〇D市 〇E郡 〇その他のA県内 〇B県 〇その他の県

ここにアンケート本文
〇車で5分以内 〇車で10分以内 〇車で20分以内 〇車で30分以内 〇それ以上


上記のように書き出すことが可能であれば、この選択肢を登録する画面や、DBへの書き込み、DBからの書き出しを検討したいと思っています。難解すぎたり、非効率であれば、別の方法を使いたいとも思っていますが、DBへの負荷?などを考えると上記のようにした方がいいような気がしています。
foreachなどをいくつか試しましたが、うまくいきませんでした。

実際には、登録状況で変わる選択肢の状態にあわせてforeachで取り出したいのですが、なかなかうまくいきません。上記のように、配列と配列じゃないものが混ざっているのはNGでしょうか?上記のような配列を作るのは、問題があるのか、また書き出し方(チェックボックスやHTMLタグは不要ですが、条件分岐やループの回し方を知りたいです)等、お知恵をお借りできればと思っています。

お手数おかけしますが、よろしくお願いします。

追記
あやふやな質問で申し訳ありません。
具体的に、
・選択肢の数だけループを回したいと思っています。
・配列の中身が、配列だったり連想配列だったりしていますが、その状況にあわせたループの作り方がわかりません。
・配列の中身を下記のようなループで表現したいのですが、どのようにしたらいいかわかりませんでした。

大外のループ(sur1,sur2,sur3などがあるだけ回す)
外のループ sur1の中の紹介、看板、チラシなどを中身のあるだけ回す。
フリーペーパー部分のような、配列を持った部分をさらにループで回す。
外のループ sur2の中身分回す
外のループ sur3の中身分回す

のようなイメージをしています。

sur1,sur2,フリーペーパーなどを直接記入せず、変数で処理できればと思います。


こちらのルール違反かもしれませんが、ご回答いただいたことをもとにまずこのようにしてみました。

<?php

$survey_q = array (
    "sur1" => "当店をお知りになったきっかけは何ですか?",
    "sur2" => "お住まいの市町村はどちらですか?",
    "sur3" => "当店におこしいただくまでの時間はどのくらいですか?",
);



$survey= array(
    "sur1"=> array("紹介",
                   "看板",
                   "チラシ",

                   "フリーペーパー" => array ("雑誌A",
                                        "雑誌B",
                                         "雑誌C",
                                         "雑誌D"),

                   "ネット" => array ("ホームページ",
                                     "EPARK",
                                     "エキテン",
                                     "LINE",
                                     "Facebook",
                                     "Instagram",
                                     "その他")
                   ),

     "sur2"=> array("A市","B市","D市","E郡","その他のA県内","B県","その他の県"),
     "sur3"=> array("車で5分以内","車で10分以内","車で20分以内","車で30分以内","それ以上")

);


foreach ($survey_q as $key => $value){
    $select_key = $key;
    print $value;
    print '<br><br>';
    //print $select_key;

    //
    foreach($survey[$select_key] as $key => $choiceData1) {
        // 複数選択肢か判定
        if(is_array($choiceData1)) {
            // 複数選択肢の項目表示
            echo $key . PHP_EOL;
            // 複数選択肢表示
            foreach($choiceData1 as $choiceData2) {
                echo $choiceData2 . PHP_EOL;
            }
        }
        else {
            // sur1,2,3直下の選択肢表示
            echo $choiceData1 . PHP_EOL;
        }
    }

    print '<br><br><br>';
}



print '<br><br><br>';




?>    

結果このように表示されました。これをもとに少しずつ目的の状態まで変えていきたいと思います。ご回答いただいた皆様、本当にありがとうございました。

当店をお知りになったきっかけは何ですか?

紹介 看板 チラシ フリーペーパー 雑誌A 雑誌B 雑誌C 雑誌D ネット ホームページ EPARK エキテン LINE Facebook Instagram その他 


お住まいの市町村はどちらですか?

A市 B市 D市 E郡 その他のA県内 B県 その他の県 


当店におこしいただくまでの時間はどのくらいですか?

車で5分以内 車で10分以内 車で20分以内 車で30分以内 それ以上 
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2017/01/16 16:15

    「うまくいきませんでした」とありますが、ご自信の試されたコードも追記されてはいかがでしょうか。

    キャンセル

  • mi_

    2017/01/16 16:30

    うまくいかなかったコードを追記しました。

    キャンセル

  • zico_teratail

    2017/01/16 16:36

    何がどう「うまくいかなかった」のですか? 最終的にどういう形にしたいのですか? 見る限り、var_dumpで必要な中身を表示できているので「うまくいっている」と思いますが。

    キャンセル

回答 3

checkベストアンサー

+3

foreachでループさせて、値が配列かテキストか判定してください。
参考:is_array

また、foreachはkey、valueを扱えます。
複数選択肢の項目(フリーペーパー、ネット)表示にはこちらを利用してください。
参考:foreach 

しかし、ご提示頂いた配列のデータでは、以下のサンプル通りループがネストし、後々バグの温床となりそうです。
扱いやすいようにフォーマットしたほうが良いかと思います。

// $surveyのforeach
foreach($survey as $surveyData) {
    // sur1,2,3のforeach
    foreach($surveyData as $key => $choiceData1) {
        // 複数選択肢か判定
        if(is_array($choiceData1)) {
            // 複数選択肢の項目表示
            echo $key . PHP_EOL;
            // 複数選択肢表示
            foreach($choiceData1 as $choiceData2) {
                echo $choiceData2 . PHP_EOL;
            }
        }
        else {
            // sur1,2,3直下の選択肢表示
            echo $choiceData1 . PHP_EOL;
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 16:58

    回答ありがとうございました。
    この複数選択しかどうかの判定ができずにいました。
    大変勉強になりました。

    初心者にはループがネストするのがうまいやり方というイメージでいましたが、見にくい?以外になにか問題がありそうでしょうか?

    別のフォーマットに変えるというご提案ですが、本当はもっと上手な構造があるのでしょうか?

    質問ばかりですみません。

    キャンセル

  • 2017/01/16 17:15

    確認いただきありがとうございます。

    今回のように使用するデータを単純に配列に格納した場合、知っている人が見る分には良いかもしれませんが、
    あとで別なコーダーが見た際に何に使用しているデータか分かりにくく、その分コストとリスクが発生します。
    また、バグについても回答させていただいた通りです。

    このあたりは変数名に正しい名前を付けるなどの目的と同義です。

    ですので、データ構造については、知見が無い人が見てもなるべくわかりやすく、単純にしておくと良いかと存じます。

    データ構造の例ですが、申し訳ありません。
    よく考えないと私の方でもいい案が浮かびませんので、今回のデータ構造については、
    今後、質問者様がプログラミングをしていく中で、ご参考いただければ幸いです。

    尚、配列の他に、jsonやObject等があります。
    こちらもご参考ください。

    キャンセル

  • 2017/01/16 17:53

    分からないことが分からない状態ですので、何を勉強していくべきか、いろいろと参考になりました。
    ありがとうございました!

    キャンセル

  • 2017/01/16 18:09

    どの回答も大変ありがたいものでしたが、そのものズバリの部分をご提示いただきましたので、ベストアンサーに選ばせていただきました。

    キャンセル

+3

DB定義

書き込みの時間などは省いていますが、以下のようなテーブル構造になるかと思います。

-- 設問テーブル

CREATE TABLE `question` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `sentence` varchar(256) NOT NULL DEFAULT '' COMMENT '質問文',
  `orderNumber` int(11) DEFAULT NULL COMMENT '表示順',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='設問';

-- 選択肢テーブル

CREATE TABLE `choice` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `parentId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '親ID',
  `questionId` int(10) unsigned DEFAULT NULL COMMENT '設問ID',
  `sentence` varchar(1000) DEFAULT NULL COMMENT '選択肢文言',
  `orderNumber` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '表示順',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COMMENT='選択肢';

-- 回答テーブル

CREATE TABLE `answer` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `userId` int(10) unsigned NOT NULL COMMENT 'ユーザーID',
  `questionId` int(10) unsigned NOT NULL COMMENT '設問ID',
  `choiceId` int(10) unsigned NOT NULL COMMENT '選択肢ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='回答';

サンプルデータ

INSERT INTO `question` (`id`, `sentence`, `orderNumber`)
VALUES
    (1,'職場までの通勤時間は?',2),
    (2,'この案件を何で知りましたか?',1);

INSERT INTO `choice` (`id`, `parentId`, `questionId`, `sentence`, `orderNumber`)
VALUES
    (1,0,1,'車で5分以内',1),
    (2,0,1,'車で10分以内',2),
    (3,0,1,'車で20分以内',3),
    (4,0,1,'車で30分以内',4),
    (5,0,1,'それ以上',5),
    (6,0,2,'紹介',1),
    (7,0,2,'看板',2),
    (8,0,2,'チラシ',3),
    (9,0,2,'フリーペーパー',4),
    (10,9,2,'雑誌A',5),
    (11,9,2,'雑誌B',6),
    (12,9,2,'雑誌C',7),
    (13,9,2,'雑誌D',8),
    (14,0,2,'ネット',9),
    (15,14,2,'ホームページ',10),
    (16,14,2,'EPARK',11),
    (17,14,2,'エキテン',12),
    (18,14,2,'LINE',13),
    (19,14,2,'Facebook',14),
    (20,14,2,'Instagram',15),
    (21,14,2,'その他',16);

この質問内容について、問題が複雑になっているのは、選択肢がツリー構造になっている点です。
ツリー構造がなければ、難易度はかなり低くなるのですが、ツリー構造が必須となると、MVCの知識がないと理解は難しいかと思われます。
まずは、ここまで理解できますでしょうか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 19:02

    まったく問題ありません。
    Quitaは先ほどユーザー登録したくらいの状態でして、掲載されたときには教えていただけると大変ありがたいです。

    キャンセル

  • 2017/01/16 19:04

    Quitaで私のアカウントをフォローしておけば、フィードに表示されます。

    キャンセル

  • 2017/01/16 19:07

    できました。
    ありがとうございました!

    キャンセル

+2

arrayになっている部分が配列になります。

$survey= array(
"sur1"=> "val"

上記の場合、以下のようにすると、文字列"val"が取得できます。
$survey["sur1"] 

"sur1"の部分に何が入るのかも不明な場合

foreach ($survey as $key => $val) {
}
とすることで、$keyに"sur1"、$valに"val"を取得できます。

$survey= array(
    "sur1"=> "val1",
    "sur2"=> "val2",
    "sur3"=> "val3",
    );


上記のような場合、sur1,val1, sur2,val2, sur3,val3
がそれぞれ取得できます。

もし、文字列"val1"ではなく、arrayかもしれない場合、

foreach ($survey as $key => $val){
  if (is_array($val)) {
    foreach ($val as $subval) {
    }
  } else {
    // string
  }
}


という感じで参照する。

subvalが配列かハッシュかを判断するのであれば、

function is_assoc($_array) { 
    if ( !is_array($_array) || empty($array) ) { 
        return -1; 
    } 
    foreach (array_keys($_array) as $k => $v) { 
        if ($k !== $v) { 
            return true; 
        } 
    } 
    return false; 
} 

http://php.net/manual/ja/function.is-array.php

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/16 17:46

    具体的にありがとうございます!
    今後も見直させていただき、活用させていただきたいと思います。

    キャンセル

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

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る