Laravel 仅当表单值存在时更新字段

Laravel 仅当表单值存在时更新字段,laravel,laravel-4,eloquent,Laravel,Laravel 4,Eloquent,我使用表单模型绑定,并使用fill()和save()方法更新数据库 激发我的editAccount控制器方法: $rules = array( 'name' => array('required'), 'email' => array('required'), 'password' => array('confirmed') ); $validator = Validator::make(Input::all(), $rules); if ($validator

我使用表单模型绑定,并使用fill()和save()方法更新数据库

激发我的editAccount控制器方法:

$rules = array(
  'name' => array('required'),
  'email' => array('required'),
  'password' => array('confirmed')
);

$validator = Validator::make(Input::all(), $rules);

if ($validator->fails())
{
 // Redirect
}

// Save to DB
$account->fill(Input::all());
$account->save();
这很好,但是如果没有提供密码(因为用户不想更新/修改密码),那么数据库中的密码字段将设置为null。因此,我只希望在通过表单提供新密码值时更新密码字段

我知道我可以做到以下几点:

// Set the fields manually
$account->name = Input::get('name');
$account->email = Input::get('email');

// Only update the password field if a value is supplied
if (Input::get('password')) {
    $account->password = Input::get('password');
}
$account->save();

但是我想知道是否有更干净的方法来处理这个问题?就像Laravel/Eloquent中的UpdateOnlyIfValueExists()方法一样。

我将坚持后面的示例。另一个选项是使用检查那里的值,如果值为空则不更新。但在我看来,雄辩者不应该为此负责


我还避免将所有输入与
fill()
一起使用。只选择您想要的。

创建基本模型并覆盖更新功能,如

/**
 * @param array $attributes
 * @return mixed
 */
public function update(Array $attributes = array()){
    foreach($attributes as $key => $value){
        if(!is_null($value)) $this->{$key} = $value;
    }
    return $this->save();
}
使用后:

$model = Model::find($id);
$model->update(Input::only('param1', 'param2', 'param3'));

对于Laravel(和其他框架)来说,这是一个相当糟糕和常见的问题。我的解决方案类似于以前的一些

我总是在update/store方法的开头将表单data Input::all()存储在一个变量中。因为您通常至少需要两次(验证和创建/更新),所以这似乎是一个很好的实践。然后,在执行任何其他操作之前,我检查update()中是否存在密码,如下所示:

$aFormData = Input::all();

if ( !$aFormData['password'] )
  unset( $aFormData['password'] );

... the rest of your code here using $aFormData ;) ...
就这样,希望能有帮助

使用
Input::only('foo','bar')
将只获取完成请求所需的值,而不是使用
Input::all()

但是,如果输入中不存在“foo”或“bar”,则该键的值将为
null

$input = Input::only('foo', 'bar');
var_dump($input);

// Outputs
array (size=2)
  'foo' => null
  'bar' => null
要以干净的方式进行筛选,请使用
null
值的任何值:

$input = array_filter($input, 'strlen');

在您的示例中,这将替换为:
$account->fill(Input::all())

检查此项,您可以验证输入中是否存在密码,并将其从批量分配中排除。您可以使用Input::Exception和Input::仅用于此目的

public function update ($id) {
    $user = User::findOrFail ($id);
    if (Input::get ('password') == '') {
        $user->update (Input::except ('password'));
    }
    else {
        $user->update (Input::all ());
    }

    //return something
}

这只会在密码不为null时更新密码

更干净的方法是使用

在任何情况下,您都不允许使用
null
或空字符串作为密码,以便您可以在
帐户
模型中安全地定义以下mutator

// Only accept a valid password and 
// hash a password before saving
public function setPasswordAttribute($password)
{
    if ( $password !== null & $password === '' )
    {
        $this->attributes['password'] = bcrypt($password);
    }
}

如果密码属性不是
null
且为空字符串,则上述mutator将仅设置密码属性。它还可以在保存密码之前对密码进行哈希运算,这样您就不需要在其他地方的控制器操作或应用程序中执行此操作。

最好的方法是使用上面诺曼·乌尔·雷曼(Noman Ur Rehman)所说的变种,但他的代码中有错误。正确的答案是:

public function setPasswordAttribute($password){
   if ( $password !== null && $password !== '' )
      $this->attributes['password'] = Hash::make($password);
}

关于为什么应该避免使用Input::all(),您是否有任何参考资料?我找不到任何应该避免的理由。如果您有任何其他
用户
字段可以通过批量分配填充,则有人可以使用该列名创建任意字段,并在不进行任何检查的情况下更改值。只收集您打算使用的内容是一种很好的做法。我理解这一点,但正确使用模型的受保护或可填充属性(我已经这样做了)。然后,Input::all和手动填充字段之间本质上没有安全风险。如果要添加一个字段并更改
$filleble
数组,或者希望在一个表单上可填充项,而不是在另一个表单上,则可能会导致问题。是的,只要采取正确的步骤,您就可以保护它,并且仍然使用
Input::all()
,我只是提出一个建议,提供额外的保护。它也更详细地描述了你需要什么样的输入,而不是只说全部。使用任何让你高兴的东西我保证,在这之后我会停止争论我反对你主张不做集体作业比做集体作业更安全的说法,那根本不是真的。我同意,一个人可以把集体作业搞砸,做得“不对”,但这不是真的吗?毕竟,你可以用PHP做无数错事,根据你的推理,你应该提倡抛弃PHP,转而使用强类型语言。所以,我认为你的论点应该是“不要搞砸集体作业”,而不是说它是安全的。
// Only accept a valid password and 
// hash a password before saving
public function setPasswordAttribute($password)
{
    if ( $password !== null & $password === '' )
    {
        $this->attributes['password'] = bcrypt($password);
    }
}
public function setPasswordAttribute($password){
   if ( $password !== null && $password !== '' )
      $this->attributes['password'] = Hash::make($password);
}