使用 laravel,我如何创建一个将更新一对多关系的视图?
Posted
技术标签:
【中文标题】使用 laravel,我如何创建一个将更新一对多关系的视图?【英文标题】:Using laravel, how do I create a view that will update a one-to-many relationship? 【发布时间】:2013-07-03 01:03:48 【问题描述】:我有 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');
希望到目前为止我在正确的轨道上......
我在 Contact 模型中使用了 Jeff Way 的脚手架,所以我在控制器中有这个更新方法:
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
现在,我不知道如何修改更新方法以更新电子邮件(如果已修改)并添加新电子邮件(如果已输入)。如果有人能指出我正确的方向,我将不胜感激 - 谢谢!
【问题讨论】:
你可以使用push()
方法来保存模型和关系link
谢谢,这可能是正确的方向,我不确定 - 但我肯定需要更多帮助。我如何让它更新 emails 表中的相应行并在它不存在时添加一个?
【参考方案1】:
这个问题的答案不一定是 Laravel 特定的答案。
无论如何,您需要处理将联系人的电子邮件与表单中提交的内容同步:
两种策略:
-
删除与该联系人关联的所有电子邮件。然后根据表单中的内容创建新电子邮件。这样一来,您始终可以插入新电子邮件。
获取与联系人关联的所有电子邮件。遍历它们。如果提交的电子邮件的 ID(来自表单)与现有电子邮件匹配,请更新该电子邮件地址。如果电子邮件是新的(没有与之关联的 ID),请创建一个新电子邮件。此选项可能需要嵌套循环,并且在技术上应该不赞成 - 但是,对于少量电子邮件,这没什么大不了的。
现在,获取 Laravel(4)-specific
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=""
属性与正确的文本字段匹配。我将把它留给你。
然后,在 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 循环中根据需要更新它们(此处未写出) .
这样的事情应该会让你开始……
【讨论】:
以上是关于使用 laravel,我如何创建一个将更新一对多关系的视图?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 php Laravel 中的两个表之间创建一对多关系?
在 laravel 中具有雄辩关系的更新期间从空值创建默认对象