Laravel保存多部分表格

I have a 3 part form that I want to be able to update the database after each submit. There is one table that holds all the fields below.

form1 asks for first and last name
form2 asks for email and phone
form3 asks for city and state

In my controller I have 3 separate functions to save each step of the form:

public function name(Request $request){
    $lead = Lead::firstOrNew(123);
    $lead->firstName = $request->get('firstName ');
    $lead->lastName = $request->get('lastName');
    $lead->save();
    return redirect('/form2');
}

public function info(Request $request){
    $lead = Lead::find(123);
    $lead->email = $request->get('email');
    $lead->phone = $request->get('phone');
    $lead->save();
    return redirect('/form3');
}

public function address(Request $request){
    $lead = Lead::find(123);
    $lead->city = $request->get('city');
    $lead->state = $request->get('state');
    $lead->save();
    return redirect('/done');
}

Is there any way to combine that to one update function?

You could refactor the methods to call a common "update" function. See example code below.

public function name(Request $request){
    $this->update(123, $request);
    return redirect('/form2');
}

public function info(Request $request){
    $this->update(123, $request);
    return redirect('/form3');
}

public function address(Request $request){
    $this->update(123, $request);
    return redirect('/done');
}

private function update($id, $request) {
    $lead = Lead::find($id);
    foreach ($field as ['firstName', 'lastName', ...]) {
        if ($request->has($field)) {
            $lead->{$field} = $request->get($field);
        }
    }
    $lead->save();
}

Just do conditional check, update the model and define redirect url:

public function info(Request $request) {
    $lead = Lead::firstOrNew(123);

    if ($request->has('firstName') && $request->has('lastName')) {
        $lead->firstName = $request->get('firstName ');
        $lead->lastName = $request->get('lastName');
        $redirect = '/form2';
    } else if ($request->has('email') && $request->has('phone')) {
        $lead->email = $request->get('email');
        $lead->phone = $request->get('lastName');
        $redirect = '/form3';
    } else if ($request->has('city') && $request->has('state')) {
        $lead->city = $request->get('city');
        $lead->state = $request->get('state');
        $redirect = '/done';
    }

    $lead->save();

    return redirect($redirect);
}

Also, you can probably do group update via update just make sure you whitelist the attributes in your model

public function info(Request $request) {
    $lead = Lead::firstOrNew(123);
    $lead->update($request->all());

    if ($request->has('firstName') && $request->has('lastName')) {
        $redirect = '/form2';
    } else if ($request->has('email') && $request->has('phone')) {
        $redirect = '/form3';
    } else if ($request->has('city') && $request->has('state')) {
        $redirect = '/done';
    }

    return redirect($redirect);
}

Or I'd better just add a redirect variable to your form like:

<input type="hidden" name="redirect" value="form1">

and simplify your controller method like:

public function info(Request $request) {
    $lead = Lead::firstOrNew(123);
    $lead->update($request->all());

    return redirect($request->input('redirect'));
}

You can add a hidden field to all three forms (but with the name name, e.g form_name), and set their values to identify the form (form1, form2, form3) when it is submitted. Then in your controller, you check the value of the form_name field on the request to determine where you want to redirect to, like this:

public function info(Request $request) {
    $lead = Lead::firstOrNew(123);
    $lead->update($request->all());

    //this will be from the hidden field (form_name)
    $form_type = $request->get('form_name');

    if ($form_type == 'form1') {
        $redirect = '/form2';
    } else if ($form_type == 'form2') {
        $redirect = '/form3';
    } else if ($form_type == 'form3') {
        $redirect = '/done';
    }

    return redirect($redirect);
}

If you have the option for using javaScript then save the first and second form data on cookies or local storage and when the user reaches last part of the form then take data out of cookies or local storage then added with the last form, but keep these in the hidden input.

Given that HTTP requests are stateless (which means each request know nothing about the one before and after it), I would rather prefer you use sessions, so that you can be able to store information as you redirect from one form to the other. In that case, your code should look like so:

<?php

public function name(Request $request){
    Session::put('nameData', $request->all());   //Store the info from form1 in session and redirect to form2
    return redirect('/form2');
}

public function info(Request $request){
    $validSessionData = Session::has('nameData');

    if (!$validSessionData) {    //Check if the user filled form1, if not, go back to form1
        return redirect('/form1');
    }

    $nameAndInfo = Session::pull('nameData', []) + $request->all();  //Merge the info from form1 with info from form2. You could decide to keep them separate and merge later.

    Session::put('nameAndInfo', $nameAndInfo);
    return redirect('/form3');
}

public function address(Request $request){
    $validSessionData = Session::has('nameAndInfo');

    if (!$validSessionData) {   Another check. You could also extend this by checking for form2 session data
        return redirect('/form1');
    }

    $allData = Session::pull('nameAndInfo', []) + $request->all();  //Merge all session data
    $lead = Lead::firstOrNew(123);
    $lead->firstName = $allData['firstName'];
    $lead->lastName = $allData['lastName'];
    $lead->email = $allData['email'];
    $lead->phone = $allData['phone'];
    $lead->city = $allData['city'];
    $lead->state = $allData['state'];

    $lead->save();
    return redirect('/done');
}