Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

SeanIz's avatar

Problem when saving data in multistep form.

I'm making a multi-step questionnaire, here's a lil bit of my code from my controller:

public function FirstPage(Request $request, Survey $survey)
    {
        $class = $survey->questions->where('category', 'Class');

        return view('questionnaire.firstpage', compact('survey', 'class'));
    }

    /**
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function storeFirstPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $responses = new SurveyResponse();
        $responses-> fill($data);
        $request->session()->put('responses', $responses);

        return redirect('questionnaire/'.$survey->id.'-'.Str::slug($survey->title).'/next');
    }

I repeat that code for the next few pages and when I reach my final page, my code is:

public function ThirdPage(Request $request, Survey $survey)
    {
        $RAID = $survey->questions->where('category', 'RAID');

        return view('questionnaire.thirdpage',compact('survey', 'RAID'));
    }
  
    /**
     * @return \Illuminate\Http\Response
     */
    public function storeThirdPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $responses = $request->session()->get('responses');
        $responses->save();

        return redirect('/results');
    }

Everything seems to work fine until I reach the last page and I submit my data. This is the error I received:

Argument 1 passed to Illuminate\Database\Grammar::parameterize() must be of the type array, string given, called in C:\Users\user\MyFile\vendor\laravel\framework\src\Illuminate\Database\Query\Grammars\Grammar.php on line 884

I'm not sure what went wrong, but I think it has to do with this specific line of code:

$responses = $request->session()->get('responses');
        $responses->save();

Would be glad to receive any help at all, thanks in advance. :)

0 likes
13 replies
automica's avatar

@seaniz what does the following give you?

$responses = $request->session()->get('responses');
dd($responses);

seems it might be to do the structure of your responses data rather than trying to save it.

you don't appear to be doing anything with the data you are passing into storeThirdPage after you've validated it. Don't you want to be adding this to the responses data before saving it?

1 like
GeordieJackson's avatar

@seaniz If you use $request->session()->put('responses', $responses); the put() method will overwrite the session data each time.

It would be better to create an array and push() your responses onto it each time.

e.g. in storeFirstPage try:

if ( ! $request->session()->exists('responses')) {
    $request->session()->put('responses', []);
}

$request->session()->push('responses', $responses);

Or similar (this is off the top of my head!)

And remember to $request->session()->forget('responses'); after you save them.

1 like
SeanIz's avatar

Thanks for replying @automica @geordiejackson. :)

As requested @automica

App\SurveyResponse {#287 ▼
  #guarded: []
  #connection: null
  #table: null
  #primaryKey: "id"
  #keyType: "int"
  +incrementing: true
  #with: []
  #withCount: []
  #perPage: 15
  +exists: false
  +wasRecentlyCreated: false
  #attributes: array:3 [▼
    "responses" => array:4 [▼
      9 => array:4 [▼
        "question_tag" => "Attribute 1"
        "question_id" => "9"
        "answer_id" => "1"
        "question_category" => "RAID"
      ]
      10 => array:4 [▼
        "question_tag" => "Attribute 2"
        "question_id" => "10"
        "answer_id" => "2"
        "question_category" => "RAID"
      ]
      11 => array:4 [▼
        "question_tag" => "Attribute 3"
        "question_id" => "11"
        "answer_id" => "2"
        "question_category" => "RAID"
      ]
      12 => array:4 [▼
        "question_tag" => "Attribute 4"
        "question_id" => "12"
        "answer_id" => "2"
        "question_category" => "RAID"
      ]
    ]
    "updated_at" => "2020-10-31 02:43:58"
    "created_at" => "2020-10-31 02:43:58"
  ]
  #original: []
  #changes: []
  #casts: []
  #classCastCache: []
  #dates: []
  #dateFormat: null
  #appends: []
  #dispatchesEvents: []
  #observables: []
  #relations: []
  #touches: []
  +timestamps: true
  #hidden: []
  #visible: []
  #fillable: []
}

The array at #attributes are the answers from my ThirdPage.

===

@geordiejackson

I tried out your suggestion on all three pages of my store method. I'm not sure how the code should be placed so I did this, haha:

 public function storeFirstPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $responses = new SurveyResponse();
        $responses-> fill($data);
        if ( ! $request->session()->exists('responses')) {
            $request->session()->put('responses', []);
        }
        
        $request->session()->push('responses', $responses);

        return redirect('questionnaire/'.$survey->id.'-'.Str::slug($survey->title).'/origin');
    }

And I repeat that for the 2nd and 3rd page's store method. I think that would help add the data in storeThirdPage like what @automica suggested.

    public function storeThirdPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $responses = new SurveyResponse();
        $responses-> fill($data);
        if ( ! $request->session()->exists('responses')) {
            $request->session()->put('responses', []);
        }
        
        $request->session()->push('responses', $responses);

        $save = $request->session()->get('responses');
        
        $save->save();
  
        $request->session()->forget('responses');        

        return redirect('/results');
    }

It returned this:

Too few arguments to function Illuminate\Database\Eloquent\Model::setAttribute(), 1 passed in C:\Users\user\myFile\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php on line 691 and exactly 2 expected
SilenceBringer's avatar

Hi @seaniz you have array in responses attribute, but do you have correct casts and database field for it?

Chek you have cast responses as array and have json column for responses in your database

1 like
SeanIz's avatar

@silencebringer Thanks for replying!

I added the protected $casts into my SurveyResponse Model, although I'm not too sure if this is the right way to do it, sorry. :(

class SurveyResponse extends Model
{
    protected $guarded = [];

    protected $casts = [
        'responses' => 'string',
    ];
    
    public function questionnaire()
    {
        return $this->belongsTo(Questionnaire::class);
    }
}

Here's my SurveyResponse table in case it's needed.

Schema::create('survey_responses', function (Blueprint $table) {
    $table->id();
    $table->foreignId('questionnaire_id')->constrained()->onDelete('cascade');
    $table->foreignId('question_id')->constrained()->onDelete('cascade');
    $table->foreignId('answer_id')->onDelete('cascade');
    $table->string('question_tag');
    $table->string('question_category');            
    $table->timestamps();
});

After adding the casts, I got this error:

Call to a member function save() on array

The problem is referenced to this code (particularly the $save->save();):

        $save = $request->session()->get('responses');

        $save->save();

Sorry if I'm not getting something simple and obvious, I'll try to look out for the solutions as well, but any help is much appreciated. :)

automica's avatar

@seaniz iif you have got an array of responses at 3rd step then how about just using a create?

$result = SurveyResponse::create($responses)
1 like
SilenceBringer's avatar
Level 55

@seaniz you are doing it completely wrong =) You want to store a set or records, but try to save it in 1 model. Of course it not working =)

I think it should be something like

    public function storeFirstPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses' => 'required|array',// just to be sure we have array of responses
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $request->session()->put('responses', $data['responses']);

        return redirect('questionnaire/'.$survey->id.'-'.Str::slug($survey->title).'/next');
    }

    public function storeThirdPage(Request $request, Survey $survey)
    {
        $data = $request->validate([
            'responses' => 'required|array',// just to be sure we have array of responses
            'responses.*.question_tag' => 'required',
            'responses.*.question_id' => 'required',
            'responses.*.answer_id' => 'required',
            'responses.*.question_category' => 'required',
        ]);

        $responses = array_merge(
            $request->session()->get('responses'),
            $data['responses']
        ); // similar thing on the second step
        
        // HERE IS THE IMPORTANT THING
        // your responses related to questionaire, so, you need to get it
        $questionnaire = Questionnaire::first(); // replace it with your logic to get current questionnaire

        // assuming you have `surveyResponses` relationship defined in questionnaire model
        $questionnaire ->surveyResponses()->createMany($responses);

        return redirect('/results');
    }
1 like
SeanIz's avatar

@silencebringer Thanks a lot, it worked. :) Thanks for breaking it down for me in detail so I understood what you were doing, it helped increase my understanding on eloquent by a mile.

And thank you @geordiejackson and @automica as well for helping me out!

Please or to participate in this conversation.