PHPでController→View→Controllerに配列を渡す方法

PHP の MVC 初心者が Controller から View に、また View から配列を渡せないかどうか実験したメモです。

目次

配列はController→Viewに渡せない?

PHPで淡々とコードを書いている時に、正解が2つある問題の処理をどうするか考えていた。

配列を $_SESSION を使って渡すことはできます。

PHP(Controller-問題)
public function __construct()
{
    session_start();
}

// スタート時にセッションを持たせる
public function start(){
    $_SESSION['quiz'] = [
        'current' => 1,
    ];
    $this->question();
}

public function question()
{
    
    // 問題セッションの初期化
    if (!isset($_SESSION['quiz'])) {
        $_SESSION['quiz'] = [
            'current' => 1,
            'questions' => [],
        ];
    }
...

$reading_count = 0;
$before_id = 0;
$correct_array = [];
foreach ($tmp_question as $k1 => $v1){
    foreach ($reading as $k2 => $v2){
        if($v1['id'] === $v2['question_id']){

            // 正解(複数ある場合を考慮)
            if ($before_id === $v2['question_id']){
                $reading_count++;
                $question[$k1]['reading'][$reading_count] = $v2['reading'];
            }else{
                $question[$k1]['reading'][0] = $v2['reading'];
                $reading_count = 0;
            }
            $before_id = $v2['question_id'];
        }
    }
}
// セッションに保存
$_SESSION['quiz']['question'] = $question;

...

// セッションの値を変数に保存
$current = $_SESSION['quiz']['current'];
$question = $_SESSION['quiz']['question'];

array_pushを使った方が良かったと思うけれど、わかりやすくcount用変数を使って書きました。

それをセッションに持たせ、Viewで使える変数に保存してViewを表示するという流れです。

そして、ViewからControllerに値を取得する時は$_POSTで取得するのがベストかなと思います。

ただ、上記でいうと$question[(n)][reading]はまだ配列の状態なんですよね。

この状態でtype=”hidden”にしたフィールドのvalueに配列を入れるとエラーになります。

これをどうにか渡せないものか・・・

なので、配列の個数分 type=”hidden” フィールドを作ってPOSTで送った先のControllerで配列を作ることにした。

HTML(View)
<?php foreach($question['reading'] as $k => $v):?>
  <input type="hidden" name="correct_<?=$k?>" value="<?=$v?>">
<?php endforeach; ?>
<input type="hidden" name="correct_count" value="<?= count($question['reading']) ?>">
PHP(Controller-回答処理)
// 解答の配列
$correctReadings = [];
$correct_count = (int)$_POST['correct_count'];
for($i=0;$i<$correct_count;$i++){
    $tmp_correct = $_POST['correct_'.$i];
    array_push($correctReadings,$tmp_correct);
}
$answer  = trim($_POST['answer']);

// セッションに情報を保持
$_SESSION['quiz']['results'][] = [
    'answer' => $answer,
    'correct' => $correctReadings,
    'is_correct' => in_array($answer, $correctReadings, true)
];

とりあえずことで成功しました。

name属性にあることをするとvalueに配列を持てる

成功したのはいいものの、なんかコードが長すぎるよなぁ・・・

と、調べたところ、name属性の値に「[ ]」を付ければ、valueに配列を持てるらしい。

HTML(View)
<?php foreach($question['reading'] as $k => $v):?>
  <input type="hidden" name="correct[]" value="<?= $v ?>">
<?php endforeach; ?>

つまり、上の例だと「correct」→「correct[]」にするだけで、valueに配列が入る。

え、何それだけ?

PHP(Controller-回答処理)
var_dump($_POST['correct']);

確かに、POSTされてきた値をvar_dumpすると、先ほど作った配列と同じだ・・・

例):薔薇(音読み)

array(2) { [0]=> string(12) “しょうび” [1]=> string(9) “そうび” }

うーん、無知は罪ですね(泣)

他の配列を渡す方法

compact()

値を整理する意図を明確にしたい場合、下記のように書く場合もあるそうです。

PHP(Controller-問題)
$current = $_SESSION['quiz']['current'];
$question = $_SESSION['quiz']['question'];

$viewData = compact('question', 'current');
extract($viewData);

require __DIR__ . '/../Views/quiz/question.php';
HTML(View)
<?php foreach($question[$current - 1]['reading'] as $k => $v):?>
  <input type="hidden" name="correct[]" value="<?= $v ?>">
<?php endforeach; ?>

Session

$_SESSIONにさらに$_SESSIONを重ねることもできます。

PHP(Controller-問題)
$_SESSION['quiz']['question'] = $question;
HTML(View)
<?php
$question = $_SESSION['quiz']['question'][$_SESSION['quiz']['current'] - 1];
?>

おまけ:implode

配列を指定の文字列で区切って出力します。

PHP
// 回答処理
public function answer(){

  ...

  // セッションに情報を保持
  $_SESSION['quiz']['results'][] = [
      'correct' => $correct,
  ];
}

// 結果表示
public function result()
{
    $results = $_SESSION['quiz']['results'];
}
HTML(View)
  <table class="w-full border-collapse border border-gray-400">
    <thead>
      <tr>
        <th class="border border-gray-300">正解</th>
      </tr>
    </thead>
    <tbody>
      <?php foreach ($results as $k => $r): ?>
      <tr>
        <td class="border border-gray-300 text-center"><?= htmlspecialchars(implode('/',$r['correct'])) ?></td>
      </tr>
      <?php endforeach; ?>
    </tbody>
  </table>

配列としてそのまま出力するより、断然それっぽくなりました。

  • URLをコピーしました!
目次