简体   繁体   English

空字符串而不是空值Eloquent

[英]Empty string instead of null values Eloquent

I'm trying to create entities using mass-assignment Eloquent feature... 我正在尝试使用质量分配Eloquent功能创建实体...

$new = new Contact(Input::all());
$new->save();

The problem's that this way, every field's filled out with an empty string instead of null values as I expected. 问题就是这样,每个字段都填充了一个空字符串而不是我期望的null值。

I'm currently developing the system and still some table columns're not defined, that's why using this method, to avoid adding every new field to $fillable array and to a new Contact(array(...)); 我正在开发系统,但仍然没有定义一些表列,这就是为什么使用这种方法,以避免将每个新字段添加到$fillable数组和new Contact(array(...)); ... ...

Also I've around 20 fields in this table, so It'd be a bit ugly to have an array such as 此外,我在这个表中有大约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' => ...
    ...
));

Any tips of how to do this or fix? 有关如何执行此操作或修复的任何提示?

Update By now I've sorted out this doing the array_filter in the App::before() filter. 更新到现在为止,我已经在App::before()过滤器中完成了这个做array_filter。

Update In filter was a bit mess. 更新过滤器有点乱。 I end up doing: 我最终做了:

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);
}

And in my functions.php. 在我的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)));
    }
}

By now only working with fields that ends with "_id". 现在只处理以“_id”结尾的字段。 This is my biggest problem as if a relationship is not NULL , the database will throw an error as the foreign key "" cannot be found. 这是我最大的问题,如果关系不是NULL ,数据库将抛出错误,因为无法找到外键“”。

Works perfect. 工作完美。 Any comment? 任何意见?

I've looked for the answer to this myself, and the closest I can come up with is using Mutators ( http://laravel.com/docs/eloquent#accessors-and-mutators ). 我自己已经找到了答案,而我最接近的就是使用Mutators( http://laravel.com/docs/eloquent#accessors-and-mutators )。

The same problem was solved by adding a (magic!) Mutator method for the foreign key field in the model: 通过为模型中的外键字段添加(magic!)Mutator方法解决了同样的问题:

public function setHeaderImageIdAttribute($value)
{
    $this->attributes['header_image_id'] = $value ?: null;
}

For a table with a lot of foreign keys, this can get kind of bulky, but it's the most "built-in" method I've found for handling this. 对于一个包含大量外键的表,这可能会变得笨重,但它是我发现处理这个问题的最“内置”方法。 The upside is that it's magic, so all you have to do is create the method and you're good to go. 好处是它很神奇,所以你所要做的就是创造方法并且你很高兴。

UPDATE -- Laravel 5.4 and above 更新 - Laravel 5.4及以上

As of Laravel 5.4, the \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class middleware handles this when the request is received. 从Laravel 5.4开始, \\Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull::class中间件在收到请求时处理此问题。 In my example above, if the request contains an empty string value for 'header_image_id', this middleware automatically converts it to null before I can assign it to my model. 在上面的示例中,如果请求包含“header_image_id”的空字符串值,则此中间件会自动将其转换为null然后才能将其分配给我的模型。

Laravel 4 Laravel 4

If it is necessary you could remove any empty string in an array by filtering . 如果有必要,可以通过过滤删除数组中的任何空字符串。

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

Then if you have something like array('a' => 'a', 'b' => '') you will get: array('a' => 'a') . 然后,如果你有类似array('a' => 'a', 'b' => '')你会得到: array('a' => 'a')

As far as I know, if a field is not specified in the array for mass-assignment, then Laravel Eloquent ORM will treat it like NULL . 据我所知,如果未在数组中指定用于质量分配的字段,则Laravel Eloquent ORM会将其视为NULL


Laravel 5 Laravel 5

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

or 要么

// If you inject the request.
$input = array_filter($request->all(), 'strlen');

Probably more generic solution: 可能更通用的解决方案:

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;
        });

    }

}

The model where you needs to sanitize empty form fields should extends this class, then you should fill $forcedNullFields array with field names that required to be NULL in case of empty form fields: 您需要清理空表单字段的模型应该扩展此类,然后您应该填充$ forcedNullFields数组,其字段名称在空表单字段的情况下必须为NULL:

class SomeModel extends EloquentBaseModel {
    protected $forcedNullFields = ['BirthDate','AnotherNullableField'];
}

And thats all, you should not repeat same code in mutators. 这就是全部,你不应该在mutators中重复相同的代码。

Use the model 'saving' event to look for empty models and explicitly set them to null. 使用模型“save”事件查找空模型并将其显式设置为null。 'Project' is the name of my model in this example. “Project”是此示例中我的模型的名称。 Put this in a helper function and wire it up to all your models. 将它放在辅助功能中并将其连接到所有型号。

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

    return true;
});

UPDATE FOR LARAVEL 5 (April 11 2016) LARAVEL 5更新(2016年4月11日)

I also ended up creating an Http Middleware to cleanup the input data from the http request, in addition to cleaning up the data before it is sent to the database. 除了在将数据发送到数据库之前清理数据之外,我还最终创建了一个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);
    }
}

For a form input, it's normal, and more logical to have empty values, rather then null values. 对于表单输入,具有空值,而不是空值,这是正常的,更合乎逻辑。

If you really think the best way to do this, is to directly put the input into your database, than the solution to make empty values null would be something like this. 如果你真的认为最好的方法就是直接把输入放到你的数据库中,那么使空值为null的解决方案就是这样的。

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

Personally I don't approve with these kind of solutions, but it does work for some people. 我个人不赞成使用这些解决方案,但它确实适用于某些人。

Another simple solution is to create base model class and extend models from it: 另一个简单的解决方案是创建基本模型类并从中扩展模型:

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);
    }
}

Then just fill required fields in $forcedNullFields for each model if needed. 然后,如果需要,只需为每个模型填写$ forcedNullFields中的必填字段。

In your Eloquent model, make sure $guarded is empty. 在您的Eloquent模型中,确保$guarded为空。 You don't need to set $fillable . 您不需要设置$fillable

Mass assignment isn't usually a good idea, but it's OK to do in some scenarios - you must determine when. 批量分配通常不是一个好主意,但在某些情况下可以做 - 你必须确定何时。

See: http://laravel.com/docs/eloquent#mass-assignment 请参阅: http//laravel.com/docs/eloquent#mass-assignment

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM