В предыдущем уроке, мы устанавливали свойства модели через сеттеры:

<?php

$user = new \App\User();
$user->email = '[email protected]';
$user->first_name = 'Pedro';

Но это не единственный способ установки свойств. Как правило, в веб-разработке, модели создаются после заполнения формы пользователем сайта. Данные этих форм приходят на сервер в виде ассоциативного массива. Eloquent, как и большинство ORM, позволяет сразу передать этот массив в конструктор, вместо индивидуальной установки каждого свойства. Такой подход называется "mass-assignment":

<?php

// Обычно это данные пришедшие из формы
$params = ['email' => '[email protected]', 'first_name' => 'Pedro'];
$user = new \App\User($params);
$user->save();

Но если выполнить такой подход в лоб, то он завершится с ошибкой: Add [email] to fillable property to allow mass assignment on [App/User]. Чтобы понять почему так происходит, надо немного поговорить о безопасности.

Формы никогда не содержат всех полей. В каждой модели обязательно есть, по крайней мере, одно поле (id), которое нельзя давать менять. Обычно их больше, например различные поля определяющие состояние, количество денег, какие-то внутренние характеристики, которые можно менять только изнутри системы.

Но достаточно ли просто не указывать их в форме? Будет ли это безопасно? Не будет. Веб это HTTP, а значит любой человек, всегда может послать форму в нужный обработчик добавив туда все что угодно. Это автоматически означает, что передача данных пачкой в конструктор может привести к очень нежелательным эффектам. Например к изменению уровня доступа в систему:

<?php

// Предположим что в базе есть поле admin, установив которое, можно получить доступ к административной части приложения.
$params = ['email' => '[email protected]', 'first_name' => 'Pedro', 'admin' => true];
$user = new \App\User($params);
$user->save();

Во избежания подобных ситуаций, Eloquent контролирует то, что идет на вход при массовом присвоении. Делается это с помощью свойства $fillable внутри модели:

<?php

namespace App;

use \Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // Белый список. Здесь описываются допустимые поля.
    protected $fillable = ['email', 'first_name', 'last_name'];
}

Теперь указанные поля могут использоваться в конструкторе:

<?php

$params = ['email' => '[email protected]', 'first_name' => 'Pedro', 'last_name' => 'Alexandro'];
$user = new \App\User($params);
$user->save(); // Все пройдет успешно

Массовое присвоение немного отличается если мы говорим про обновление сущности. Конструктор использовать не получится, сущность уже создана. Для массового обновления полей создан метод fill:

<?php

$user = \App\User::find($id);
// Только обновление, без сохранения
// Этот метод так же ориентируется на свойство $fillable
$user->fill(['first_name' => 'Mike', 'email' => '[email protected]']);
$user->save();

Откровенно говоря, контроль входных данных это не уровень моделей. Об этом должен заботиться тот слой, который использует модели. Но жизнь сложная штука. Подобные решения принимаются разработчиками фреймворков, в угоду упрощения работы. Иначе повышается порог входа. С другой стороны, подобные вещи выходят боком для опытных разработчиков. Что если нам нужно иметь разные наборы полей для разных форм? Eloquent ничего не сможет сделать, потому что набор полей зашивается жестко внутри модели

Самостоятельная работа

  1. Заполните $fillable у User если оно не заполнено.
  2. Создайте пользователя используя mass-assignment.
  3. Обновите любого пользователя используя mass-assignment.

Дополнительные материалы

  1. Mass Assigment
Мы учим программированию с нуля до стажировки и работы. Попробуйте наш бесплатный курс «Введение в программирование» или полные программы обучения по Node, PHP, Python и Java.

Хекслет

Подробнее о том, почему наше обучение работает →