我正在尝试使用质量分配Eloquent功能创建实体...
$new = new Contact(Input::all());
$new->save();
问题是这样,每个字段都填充了一个空字符串,而不是我预期的null
值。
我目前正在开发系统,但仍未定义一些表格列,这就是使用此方法的原因,以避免将每个新字段添加到$fillable
数组和new Contact(array(...));
...
此表中我还有大约20个字段,所以拥有像
这样的数组会有点难看$new = new Contact(array(
'salutation' => Input::get('salutation'),
'first_name' => Input::get('first_name'),
'last_name' => Input::get('last_name'),
'company_id' => Input::get('company_id'),
'city' => ...
...
));
有关如何执行此操作或修复的任何提示?
更新到目前为止,我已经在App::before()
过滤器中对array_filter进行了整理。
更新在过滤器中有点乱。我最终做了:
public static function allEmptyIdsToNull()
{
$input = Input::all();
$result = preg_grep_keys ( '/_id$/' , $input );
$nulledResults = array_map(function($item) {
if (empty($item))
return null;
return $item;
}, $result);
return array_merge($input, $nulledResults);
}
在我的functions.php。
中if ( ! function_exists('preg_grep_keys'))
{
/**
* This function gets does the same as preg_grep but applies the regex
* to the array keys instead to the array values as this last does.
* Returns an array containing only the keys that match the exp.
*
* @author Daniel Klein
*
* @param string $pattern
* @param array $input
* @param integer $flags
* @return array
*/
function preg_grep_keys($pattern, array $input, $flags = 0) {
return array_intersect_key($input, array_flip(preg_grep($pattern, array_keys($input), $flags)));
}
}
现在只处理以“_id”结尾的字段。这是我最大的问题,如果关系不是NULL
,数据库将抛出错误,因为无法找到外键“”。
完美的作品。有评论吗?
答案 0 :(得分:61)
我自己已经找到了答案,而我最接近的就是使用Mutators(http://laravel.com/docs/eloquent#accessors-and-mutators)。
通过为模型中的外键字段添加(magic!)Mutator方法解决了同样的问题:
public function setHeaderImageIdAttribute($value)
{
$this->attributes['header_image_id'] = $value ?: null;
}
对于包含大量外键的表格,这可能会变得笨重,但它是我发现处理此问题的最“内置”方法。好处是它很神奇,所以你所要做的就是创造方法并且你很高兴。
更新 - Laravel 5.4及以上
从Laravel 5.4开始,\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
中间件在收到请求时处理此问题。在上面的示例中,如果请求包含“header_image_id”的空字符串值,则此中间件会自动将其转换为null
,然后才能将其分配给我的模型。
答案 1 :(得分:19)
如果有必要,可以通过过滤删除数组中的任何空字符串。
$input = array_filter(Input::all(), 'strlen');
然后,如果你有类似array('a' => 'a', 'b' => '')
的内容,你会得到:array('a' => 'a')
。
据我所知,如果数组中没有为质量分配指定一个字段,那么Laravel Eloquent ORM会将其视为NULL
。
$input = array_filter(Request::all(), 'strlen');
或
// If you inject the request.
$input = array_filter($request->all(), 'strlen');
答案 2 :(得分:11)
可能更通用的解决方案:
class EloquentBaseModel extends Eloquent {
public static function boot()
{
parent::boot();
static::saving(function($model)
{
if (count($model->forcedNullFields) > 0) {
foreach ($model->toArray() as $fieldName => $fieldValue) {
if ( empty($fieldValue) && in_array($fieldName,$model->forcedNullFields)) {
$model->attributes[$fieldName] = null;
}
}
}
return true;
});
}
}
您需要清理空表单字段的模型应该扩展此类,然后您应该填充$ forcedNullFields数组,其中字段名称在空表单字段的情况下必须为NULL:
class SomeModel extends EloquentBaseModel {
protected $forcedNullFields = ['BirthDate','AnotherNullableField'];
}
就是这样,你不应该在mutators中重复相同的代码。
答案 3 :(得分:10)
使用模型'saving'事件查找空模型并将其显式设置为null。 “Project”是此示例中我的模型的名称。将它放在辅助功能中并将其连接到所有模型。
Project::saving(function($model) {
foreach ($model->toArray() as $name => $value) {
if (empty($value)) {
$model->{$name} = null;
}
}
return true;
});
LARAVEL 5更新(2016年4月11日)
除了在将数据发送到数据库之前清理数据之外,我还最终创建了一个Http Middleware来清除http请求中的输入数据。
class InputCleanup
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$input = $request->input();
array_walk_recursive($input, function(&$value) {
if (is_string($value)) {
$value = StringHelper::trimNull($value);
}
});
$request->replace($input);
return $next($request);
}
}
答案 4 :(得分:1)
对于表单输入,它是正常的,更合乎逻辑的是具有空值,而不是空值。
如果你真的认为最好的方法就是直接把输入放到你的数据库中,那么使空值为null的解决方案就是这样的。
$input = Input::all();
foreach ($input as &$value) {
if (empty($value) { $value = null; }
}
$new = new Contact(Input::all());
$new->save();
就我个人而言,我不同意这些解决方案,但它确实适用于某些人。
答案 5 :(得分:1)
另一个简单的解决方案是创建基础模型类并从中扩展模型:
class Model extends \Illuminate\Database\Eloquent\Model
{
/**
* Set field to null if empty string
*
* @var array
*/
protected $forcedNullFields = [];
/**
* Set a given attribute on the model.
*
* @param string $key
* @param mixed $value
* @return \Illuminate\Database\Eloquent\Model
*/
public function setAttribute($key, $value)
{
if (in_array($key, $this->forcedNullFields) && $value === '') {
$value = null;
}
return parent::setAttribute($key, $value);
}
}
然后根据需要在每个模型的$ forcedNullFields中填写必填字段。
答案 6 :(得分:-2)
在您的Eloquent模型中,确保$guarded
为空。您无需设置$fillable
。
批量作业通常不是一个好主意,但在某些情况下可以做 - 你必须确定何时。