31

我正在尝试使用批量分配雄辩功能创建实体...

$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,数据库会因为找不到外键“”而抛出错误。

完美运行。任何意见?

4

7 回答 7

64

我自己寻找过这个问题的答案,我能想到的最接近的方法是使用 Mutators ( http://laravel.com/docs/eloquent#accessors-and-mutators )。

通过为模型中的外键字段添加(魔术!)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在我将其分配给我的模型之前自动将其转换为。

于 2013-07-27T00:17:38.927 回答
19

拉拉维尔 4

如果有必要,您可以通过过滤删除数组中的任何空字符串。

$input = array_filter(Input::all(), 'strlen');

然后,如果你有类似的东西,array('a' => 'a', 'b' => '')你会得到:array('a' => 'a').

据我所知,如果数组中没有指定一个字段进行批量赋值,那么 Laravel Eloquent ORM 会将其视为NULL.


拉拉维尔 5

$input = array_filter(Request::all(), 'strlen');

或者

// If you inject the request.
$input = array_filter($request->all(), 'strlen');
于 2013-07-03T16:26:22.010 回答
12

可能更通用的解决方案:

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 中重复相同的代码。

于 2014-10-28T07:47:53.977 回答
10

使用模型“保存”事件来查找空模型并将它们显式设置为空。在此示例中,“项目”是我的模型的名称。把它放在一个辅助函数中并将它连接到你的所有模型。

Project::saving(function($model) {
    foreach ($model->toArray() as $name => $value) {
        if (empty($value)) {
            $model->{$name} = null;
        }
    }

    return true;
});

Laravel 5 更新(2016 年 4 月 11 日)

我最后还创建了一个 Http 中间件来清理来自 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);
    }
}
于 2013-09-30T18:43:40.897 回答
1

对于表单输入,具有空值而不是空值是正常且更合乎逻辑的。

如果您真的认为最好的方法是直接将输入放入您的数据库中,那么将空值设为 null 的解决方案将是这样的。

$input = Input::all();
foreach ($input as &$value) {
    if (empty($value) { $value = null; }
}
$new = new Contact(Input::all());
$new->save();

我个人不赞成这种解决方案,但它确实适用于某些人。

于 2013-07-03T16:18:24.553 回答
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 中填写必填字段。

于 2018-07-06T08:26:03.900 回答
-2

在您的 Eloquent 模型中,确保$guarded为空。你不需要设置$fillable.

批量分配通常不是一个好主意,但在某些情况下可以这样做 - 您必须确定何时。

见: http: //laravel.com/docs/eloquent#mass-assignment

于 2013-07-03T16:14:15.903 回答