使用laravel,如何创建一个更新一对多关系的视图?

时间:2013-07-05 02:17:22

标签: laravel laravel-4 eloquent blade

我有2个型号,联系人和电子邮件。任何联系人都可能有多个电子邮件地址,因此我在模型中创建了一对多的关系:

class Contact extends Eloquent {

    protected $guarded = array();

    public static $rules = array(
        'first_name' => 'required',
        'last_name' => 'required'
    );

    public function emails() {
        return $this->hasMany('Email');
    }

}

class Email extends Eloquent {

    public function emails() {
        return $this->belongsTo('Contact');
    }

}

希望到目前为止我走的正确...

我已经将Jeff Way的脚手架用于Contact模型,所以我在控制器中有了这个更新方法:

public function update($id)
{
    $input = array_except(Input::all(), '_method');
    $validation = Validator::make($input, Contact::$rules);

    if ($validation->passes())
    {
        $contact = $this->contact->find($id);
        $contact->update($input);

        return Redirect::route('contacts.show', $id);
    }

    return Redirect::route('contacts.edit', $id)
        ->withInput()
        ->withErrors($validation)
        ->with('message', 'There were validation errors.');
}

此外,我修改了编辑视图以显示与该联系人关联的所有电子邮件,然后添加了一个额外的空白输入以添加新的电子邮件:

@foreach($emails as $key => $email)
    <li>
        {{ Form::label('email', 'Email '.$key.':') }}
        {{ Form::text('email'.$email->id, $email->email) }}
    </li>
    @if(count($emails)==$key+1)
    <li>
        {{ Form::label('email', 'Email '.($key+1).':') }}
        {{ Form::text('email'.($email->id+1)) }}
    </li>
    @endif
@endforeach

现在,我不知道如何修改更新方法以更新电子邮件(如果已修改)并添加新电子邮件(如果已输入)。如果有人能指出我正确的方向,我将不胜感激 - 谢谢!

1 个答案:

答案 0 :(得分:4)

答案不一定是特定于Laravel的答案。

无论如何,您需要处理将联系人的电子邮件与表单中提交的内容进行同步:

两种策略:

  1. 删除与该联系人关联的所有电子邮件。然后根据表单中的内容创建新电子邮件。这样,您总是会插入新的电子邮件。
  2. 获取与该联系人关联的所有电子邮件。通过他们迭代。如果提交的电子邮件的ID(来自表单)与现有电子邮件匹配,请更新该电子邮件地址。如果电子邮件是新的(没有与之关联的ID),请创建一个新电子邮件。这个选项可能需要一个嵌套循环,从技术上来说应该不赞成 - 但是,对于少量的电子邮件,这不是什么大问题。
  3. 现在,要获得Laravel(4)特定的

    Eloquent有一个方便的sync()方法来处理更新关系 - 但是,我相信它只适用于多对多关系,因此依赖于“数据透视表”。

    Eloquent也有一个push()方法,但由于我还没有使用它,我不确定它是否在幕后“同步”相关的电子邮件或只是添加新的关系。这是你最好的选择。

    我在推特上写信给Laravel,希望能看到一个答案:https://twitter.com/fideloper/status/353303438664278018

    对于选项1:

    首先,将所有电子邮件文本域(无论是现有的还是新的)重命名为email[]。我们不会关心他们的ID,因为它们会被删除。

    @foreach($emails as $key => $email)
        <li>
            {{ Form::label('email', 'Email:') }}
            {{ Form::text('email[]', $email->email) }}
        </li>
    @endforeach
        <!-- No need to have this in PHP logic - always give option to add new emails -->
        <!-- I'm also assuming you can name multiple new emails, perhaps with some JS -->
        <li>
            {{ Form::label('email', 'New Email:') }}
            {{ Form::text('email[]' }}
        </li>
    

    次要注意事项:您可能需要处理文本字段的ID,可能使用$key变量,因此标签for=""属性与正确的TextField匹配。我会把它留给你。

    然后,在PHP中,您将删除与$ contact关联的所有电子邮件,然后像新的一样创建它们。

    // Delete all related emails
    $contact->emails()->delete(); // I think this works. Otherwise do a manual query or loop through email email and `->delete()` them.
    
    // Create new ones
    foreach( Input::get("emails") as $email )
    {
        $newEmail = new Email;
        $newEmail->email = $email;
        $contact->emails()->save($email);
    }
    

    对于选项2:

    您将知道是否存在新电子邮件,因为它们没有与表单数据相关联的ID。我会将我的输入更改为一组电子邮件,因此循环使用它们会更容易:

    @foreach($emails as $key => $email)
        <li>
            {{ Form::label('email', 'Email '.$key.':') }}
            <!-- Notice this is an array now: -->
            {{ Form::text('email['.$email->id.']', $email->email) }}
        </li>
    @endforeach
        <!-- No need to have this in PHP logic - always give option to add new emails -->
        <!-- I'm also assuming you can name multiple new emails, perhaps with some JS -->
        <li>
            {{ Form::label('newemail', 'New Email:') }}
            {{ Form::text('newemail[]' }}
        </li>
    

    然后在PHP中,发送新电子邮件:

    foreach( Input::get('newemail') as $email)
    {
        $newEmail = new Email();
        $newEmail->email = $email;
        $contact->emails()->save( $newEmail );
    }
    

    对于上面示例中的“非新”电子邮件Input::get('email'),您可能需要获取与该联系人关联的当前电子邮件($currentEmails = $contact->emails()),并在foreach循环中根据需要更新它们(不是写在这里)。

    这样的事情应该让你开始......