PHP の MVC 初心者が Controller から View に、また View から配列を渡せないかどうか実験したメモです。
配列はController→Viewに渡せない?
PHPで淡々とコードを書いている時に、正解が2つある問題の処理をどうするか考えていた。
配列を $_SESSION を使って渡すことはできます。
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で配列を作ることにした。
<?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']) ?>">// 解答の配列
$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に配列を持てるらしい。
<?php foreach($question['reading'] as $k => $v):?>
<input type="hidden" name="correct[]" value="<?= $v ?>">
<?php endforeach; ?>つまり、上の例だと「correct」→「correct[]」にするだけで、valueに配列が入る。
え、何それだけ?
var_dump($_POST['correct']);確かに、POSTされてきた値をvar_dumpすると、先ほど作った配列と同じだ・・・
例):薔薇(音読み)
array(2) { [0]=> string(12) “しょうび” [1]=> string(9) “そうび” }
うーん、無知は罪ですね(泣)
他の配列を渡す方法
compact()
値を整理する意図を明確にしたい場合、下記のように書く場合もあるそうです。
$current = $_SESSION['quiz']['current'];
$question = $_SESSION['quiz']['question'];
$viewData = compact('question', 'current');
extract($viewData);
require __DIR__ . '/../Views/quiz/question.php';<?php foreach($question[$current - 1]['reading'] as $k => $v):?>
<input type="hidden" name="correct[]" value="<?= $v ?>">
<?php endforeach; ?>Session
$_SESSIONにさらに$_SESSIONを重ねることもできます。
$_SESSION['quiz']['question'] = $question;<?php
$question = $_SESSION['quiz']['question'][$_SESSION['quiz']['current'] - 1];
?>おまけ:implode
配列を指定の文字列で区切って出力します。
// 回答処理
public function answer(){
...
// セッションに情報を保持
$_SESSION['quiz']['results'][] = [
'correct' => $correct,
];
}
// 結果表示
public function result()
{
$results = $_SESSION['quiz']['results'];
} <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>
配列としてそのまま出力するより、断然それっぽくなりました。
