Laravel/Eloquent: проверка внутри модели

Просто разбираюсь с Laravel 4.2 и красноречиво. Я наблюдал за слепками Laravel from Scratch на laracasts.com, особенно уроки по проверке и последующему рефакторингу. Примеры, используемые в этих уроках, относятся к относительно простой пользовательской модели, в которой есть только 2 поля: имя пользователя и пароль. Моя пользовательская модель содержит гораздо больше полей, и моя регистрационная форма просит пользователя повторно ввести/подтвердить введенный пароль.

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

$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
    return Redirect::back()->withInput()->withErrors($this->user->errors);
}

Итак, я написал свои правила и заработал проверку, и теперь я готов сохранить ввод пользователя в базу данных. Однако, поскольку я заполнил свою модель всем пользовательским вводом, экземпляр пользовательской модели теперь содержит атрибут confirm_password, и вызов $user->save(); дает мне ошибку (поскольку у меня нет этого поля в моей таблице базы данных). Кроме того, поскольку я только что передал пользовательский ввод для проверки, пароль там также не хешируется.

Какой подход лучше всего использовать в отношении проверки пользовательского ввода VS, когда модель фактически представляет таблицу базы данных? Я знаю, что есть способы обойти все это, выполнив такие действия, как перемещение проверки за пределы модели и, возможно, просто позволить модели хранить правила проверки и т. д., но я могу искать советы по передовой практике.

Спасибо


person Jonathon    schedule 21.09.2014    source источник
comment
Вы можете использовать mutator для хеширования пароля и событие saving для отключения confirm_password. Однако я бы все равно не стал проводить валидацию в модели, и ваше «простое» решение, вероятно, окажется негибким и внесет больше сложности, чем кажется сейчас.   -  person Jarek Tkaczyk    schedule 21.09.2014


Ответы (2)


Вы можете удалить его перед сохранением, например:

$input = Input::all();
if (!$this->user->fill($input)->isValid()) {
    return Redirect::back()->withInput()->withErrors($this->user->errors);
}
else {
    unset($this->user->attributes['confirm_password']);
    $this->user->save();
}

Это может работать, но не является правильным способом для этого. Вы также можете использовать сохранение event, например:

// Goes in to your model
protected static function boot()
{
    parent::boot();
    static::saving(function($model) {
        unset($model->attributes['confirm_password']);
    });
}

Поскольку вы выполняете проверку внутри своей модели, вы можете инициировать проверку в событии saving, например:

protected static function boot()
{
    parent::boot();
    static::saving(function($model) {
        if($model->isValid()) {
            unset($model->attributes['confirm_password']);
            return true;
        }
        return false;
    });
}
person The Alpha    schedule 21.09.2014
comment
Спасибо за Ваш ответ. Я думаю, что сохранение события будет лучшим подходом. Возможно, я смогу использовать его для хэширования своего пароля перед сохранением. В каком случае есть способ проверить, является ли мой пароль хешированным или обычным текстом (в случае, когда я извлекаю пользователя из базы данных, атрибут пароля уже будет хэшированным)? - person Jonathon; 21.09.2014
comment
Добро пожаловать и да, я так думаю :-) - person The Alpha; 21.09.2014
comment
Любая идея, как проверить, хеширована ли строка? Глядя на документацию, кажется, что Hash имеет только 3 метода: make, check и needsRehash - person Jonathon; 21.09.2014
comment
Вам не нужно проверять, hashed это или нет, просто сделайте это внутри static::saving(function($model) {...}. - person The Alpha; 21.09.2014
comment
Но что, если я получил пользователя из базы данных с помощью User::find(1) или аналогичного, а затем решил обновить запись пользователя, внеся некоторые изменения, а затем вызвав save. Не будет ли это означать, что пароль уже будет хеширован и впоследствии будет хеширован снова при вызове сохранения? - person Jonathon; 21.09.2014
comment
Затем используйте два разных события creating и updating. - person The Alpha; 21.09.2014

Есть более приятные способы сделать то же самое.

  1. Ограничьте свои входные значения. Вы можете передать Input::all() вашему валидатору и продолжать делать это.

    $input = Input::only('username', 'password');
    // – OR –
    $input = Input::except('confirm_password');
    
  2. Добавьте $fillable в свою модель пользователя.

    class User extends Eloquent {
        protected $fillable = array('id', 'name', 'email', 'password');
    }
    

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

$user = User::create(Input::all());

Это позволит выполнить то, что вы пытаетесь сделать, не сбрасывая входные значения и не добавляя событий модели.

person Kevin G.    schedule 15.01.2015