Пустая строка вместо нулевых значений Красноречива


Я пытаюсь создавать сущности, используя красноречивую функцию массового назначения...

$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' => ...
    ...
));

Есть какие-нибудь советы, как это сделать или исправить?

Обновление К настоящему времени я разобрался с этим, выполнив array_filter в фильтреApp::before().

Обновление В фильтре было немного беспорядочно. В итоге я делаю:

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, база данных выдаст ошибку, так как внешний ключ "" не может быть нашел.

Работает идеально. Есть какие-нибудь комментарии?

Author: Israel Ortuño, 2013-07-03

7 answers

Используйте событие "сохранение" модели для поиска пустых моделей и явно установите для них значение null. "Проект" - это название моей модели в этом примере. Включите это в вспомогательную функцию и подключите ее ко всем вашим моделям.

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

    return true;
});

ОБНОВЛЕНИЕ ДЛЯ LARAVEL 5 (11 апреля 2016)

Я также закончил созданием промежуточного программного обеспечения 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);
    }
}
 10
Author: craigtadlock, 2016-04-11 23:32:28

Я сам искал ответ на этот вопрос, и самое близкое, что я могу придумать, - это использовать мутаторы (http://laravel.com/docs/eloquent#accessors-and-mutators).

Та же проблема была решена путем добавления (волшебства!) Метод мутатора для поля внешнего ключа в модели:

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

Для таблицы с большим количеством внешних ключей это может показаться громоздким, но это самый "встроенный" метод, который я нашел для обработки этого. Плюс в том, что это волшебство, так что все, что вам нужно сделать это создать метод, и вы готовы идти.

 58
Author: Trip, 2013-07-27 00:17:38

Ларавель 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');
 19
Author: Rubens Mariuzzo, 2015-12-21 10:31:23

Возможно, более общее решение:

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 именами полей, которые должны быть пустыми в случае пустых полей формы:

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

И это все, вы не должны повторять один и тот же код в мутаторах.

 11
Author: Konstantin Šuvakin, 2014-10-28 08:41:53

Для ввода формы нормально и более логично иметь пустые значения, а не нулевые значения.

Если вы действительно считаете, что лучший способ сделать это - напрямую ввести входные данные в вашу базу данных, то решение сделать пустые значения нулевыми было бы примерно таким.

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

Лично я не одобряю такого рода решения, но для некоторых людей это действительно работает.

 1
Author: Nico Kaag, 2013-07-03 16:18:24

Еще одним простым решением является создание базового класса моделей и расширение моделей на его основе:

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 для каждой модели, если это необходимо.

 0
Author: Vedmant, 2018-07-06 08:26:03

В вашей красноречивой модели убедитесь, что $guarded пустое. Вам не нужно устанавливать $fillable.

Массовое назначение обычно не является хорошей идеей, но в некоторых сценариях это нормально - вы должны определить, когда.

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

 -2
Author: Half Crazed, 2013-07-03 16:14:15