Я пытаюсь создать объекты, используя функцию Mass-assign Eloquent …
$new = new Contact(Input::all()); $new->save();
Проблема в том, что в этом случае каждое поле заполняется пустой строкой вместо null
значений, как я ожидал.
В настоящее время я разрабатываю систему, и все же некоторые столбцы таблицы не определены, поэтому с помощью этого метода следует избегать добавления каждого нового поля в $fillable
array и в 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); }
И в моих функциях.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
, база данных будет вызывать ошибку, поскольку внешний ключ «» не может быть найден.
Прекрасно работает. Есть комментарии?
Используйте событие 'save' для поиска пустых моделей и явно установите для них значение null. «Проект» – это название моей модели в этом примере. Поместите это в вспомогательную функцию и подключите ее ко всем вашим моделям.
Project::saving(function($model) { foreach ($model->toArray() as $name => $value) { if (empty($value)) { $model->{$name} = null; } } return true; });
ОБНОВЛЕНИЕ ЗА ЛАВРОВ 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); } }
Я сам искал ответ на этот вопрос, и ближе всего я могу использовать Mutators ( http://laravel.com/docs/eloquent#accessors-and-mutators ).
Эта же проблема была решена путем добавления метода (magic!) Mutator для поля внешнего ключа в модели:
public function setHeaderImageIdAttribute($value) { $this->attributes['header_image_id'] = $value ?: null; }
Для таблицы с большим количеством внешних ключей это может быть довольно громоздким, но это самый «встроенный» метод, который я нашел для обработки этого. Потенциал заключается в том, что это волшебство, поэтому все, что вам нужно сделать, это создать метод, и вам хорошо идти.
Если необходимо, вы можете удалить любую пустую строку в массиве путем фильтрации .
$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');
Вероятно, более общее решение:
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; }); } }
Модель, в которой вам нужно очищать пустые поля формы, должна расширять этот класс, тогда вы должны заполнить массив $ fixedNullFields именами полей, которые должны быть NULL в случае пустых полей формы:
class SomeModel extends EloquentBaseModel { protected $forcedNullFields = ['BirthDate','AnotherNullableField']; }
И это все, вы не должны повторять один и тот же код в мутаторах.
Для ввода формы это нормально и логичнее иметь пустые значения, а не нулевые значения.
Если вы действительно считаете, что лучший способ сделать это, это прямое внесение ввода в вашу базу данных, чем решение для пустых значений null будет выглядеть примерно так.
$input = Input::all(); foreach ($input as &$value) { if (empty($value) { $value = null; } } $new = new Contact(Input::all()); $new->save();
Лично я не одобряю подобные решения, но это работает для некоторых людей.
В своей модели Eloquent убедитесь, что $guarded
пуст. Вам не нужно устанавливать $fillable
.
Массовое назначение обычно не является хорошей идеей, но в некоторых сценариях это нормально, вы должны определить, когда.