UuyelikHesabm Benim verdiğim örneğe göre; Question içinde allows_multiple ve min_answers şeklinde iki alan var. allows_multiple bu soru birden fazla cevap içerebilir demek, min_answers ise istenen minimum cevap.
- allows_multiple false olursa o soruda checkbox kullanılamaz.
- min_answers 0 olursa o soru boş bırakılabilir.
- allows_multiple false ise min_answers 0 ya da 1 olabilir.
Bu kurallara göre soruları oluşturmalıyım. Bunları soru oluştururken kontrol etmeli ve ona göre sorunun oluşup oluşmamasına izin vermeliyim.
Soruları oluşturmak için ise;
@foreach($poll->questions as $i => $question)
<div>
<h2>{{ $i + 1}} - {{ $question->title }}</h2>
<ul>
@foreach($question->choices as $choice)
<li>
@switch($choice)
@case(ChoiceType::Checkbox)
<label>
<!-- name="answer[1][1][]" -->
<input type="checkbox"
name="{{ sprintf('answer[%d][%d][]', $question->id, $choice->id) }}"
value="{{ $choice->id }}">
<span>{{ $choice->title }}</span>
</label>
@break
@case(ChoiceType::Radio)
<label>
<!-- name="answer[1][1]" -->
<input type="radio"
name="{{ sprintf('answer[%d][%d]', $question->id, $choice->id) }}"
value="{{ $choice->id }}">
<span>{{ $choice->title }}</span>
</label>
@break
@case(ChoiceType::Input)
<label>
<!-- name="answer[1][1]" -->
<input type="text"
name="{{ sprintf('answer[%d][%d]', $question->id, $choice->id) }}">
<span>{{ $choice->title }}</span>
</label>
@break
@case(ChoiceType::Textarea)
<label>
<!-- name="answer[1][1]" -->
<textarea rows="4"
name="{{ sprintf('answer[%d][%d]', $question->id, $choice->id) }}">
<span>{{ $choice->title }}</span>
</label>
@break
@endswitch
<!-- Sorunun boş da olsa daima request içinde gelmesini sağlıyorum -->
<input type="hidden"
name="{{ sprintf('answer[%d][%d]', $question->id, $choice->id) }}"
</li>
@endforeach
</ul>
</div>
@endforeach
Bu şekilde yaptığımda $request->input('answer')
şöyle bir dizi döner:
[
1 => [
3 = > [1, 2, 3],
],
2 => [
7 = > 16,
],
3 => [
12 = > "Elle yazılmış cevap",
],
4 => [
14 => null,
]
]
Burada dizinin ilk anahtarı soru id, bir seviye derinlikteki anahtarlar ise seçenekler ve cevapları. Bu durumda
- 1 id'li soru checkbox; 3 seçenek işaretlenmiş
- 2 id'li soru radio
- 3 id'li soru input ya da textarea
- 4 id'li soru min_answers değeri 0 ve boş bırakılmış
$user = $request->user();
$poll = Poll::findOrFail($id);
if($previouslyCompletedPoll = $user->polls()->find($poll->id)) {
// Kullanıcı daha önce bu anketi doldurmuş.
// $previouslyCompletedPoll->completed_at tarihinde...
}
$allAnswers= $request->input('answers');
// Herhangi bir hata durumunda veritabanına eksik/yanlış kayıt atmaması için
// işlemleri transaction içinde yapıyorum.
DB::transaction(function() use ($request, $poll, $allAnswers) {
// Kullanıcı bu anketi doldurdu
$request->user()
->polls()
->attach($poll, [
'completed_at' => now(),
]);
foreach($poll->questions as $question) {
foreach($allAnswers[$question->id] as $choiceId => $answers) {
$common = [
'poll_id' => $poll->id,
'quesion_id' => $question->id,
'choice_id' => $choiceId,
'answer' => null,
];
// Eğer soru birden fazla cevaba izin veriyorsa demek ki cevap bir dizi
// json kullanmadığımız için her bir cevap için bir kayıt atacağız
if($question->allows_multiple && is_array($answers)) {
$createData = [];
foreach($answers as $answer) {
$common['answer'] = $answer;
$createData[] = $common;
}
$request->user()
->answers()
->createMany($createData);
} else {
$common['answer'] = $answers;
$request->user()
->answers()
->create($common);
}
}
}
});
Ben kabaca örnek vermeye çalıştım. Sizin değil kendi örneğimden yola çıktım. Hata yaptığım yerler olabilir, kafadan yazıyorum. Bir çok kontrol yapılması gerekiyor, onları yazmadım elbette. Size ne kadar açıklayabildim bilmiyorum, umarım işinize yarar.