dtf54486 2014-01-04 22:11
浏览 36
已采纳

保存后,Ardent模型不会验证

I'm having problems inserting objects in a one to many relationship. This is my code:

/** 
 * Migrations 
 **/
// Create user__groups table
Schema::create('user__groups', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name', 50);
});

// Create users table
Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->timestamps(); // created_at, updated_at DATETIME

    $table->string('username', 40);
    $table->string('password', 20);

    $table->integer('user_group_id')->unsigned();
    $table->foreign('user_group_id')->references('id')->on('user__groups');
});

/** 
 * Models 
 **/
class User extends Ardent {
    protected $table = 'users';
    public $timestamps = true;
    protected $hidden = array('password');
    public $autoPurgeRedundantAttributes = true;
    protected $fillable = array(*);

    // Validation rules for fields in this entity
    public static $rules = array(
        'username'              => 'required|unique:users',
        'password'              => 'required|alpha_dash|min:6|max:20|confirmed',
        'password_confirmation' => 'required|alpha_dash|min:6|max:20'
    );

    // Relations
    public static $relationsData = array(
        'userGroup' => array(self::BELONGS_TO, 'UserGroup')
    );

    // Model mock data for test purposes
    public static $factory = array(
        'username'              => 'string',
        'password'              => '123123',
        'password_confirmation' => '123123',
        'user_group_id'         => 'factory|UserGroup'
    );
}

class UserGroup extends Ardent {
    protected $table = 'user__groups';
    public $timestamps = false;
    public $autoPurgeRedundantAttributes = true;
    protected $fillable = array('*');

    // Validation rules for fields in this entity
    public static $rules = array(
        'name' => 'required|unique:user__groups|alpha_dash'
    );

    // Relations
    public static $relationsData = array(
        'users' => array(self::HAS_MANY, 'User')
    );

    // Model mock data for test purposes
    public static $factory = array(
        'name' => 'string'
    );
}

PHPUnit test

public function test_assignUserToGroup() {
    /* @var $user User */
    $user = FactoryMuff::instance('User');

    // Test assigning user to group 1
    $group1 = FactoryMuff::create('UserGroup');
    $this->assertTrue($group1->users()->save($user) !== false, "User model did not save!".$user->errors());

    // Test assigning user to group 2 (this fails)
    $group2 = FactoryMuff::create('UserGroup');
    $this->assertTrue($group2->users()->save($user) !== false, "User model did not update!".$user->errors()); // <-- The save method always returns false
}

The testrun will reflect that the user object will not be updated. Why? What am I doing wrong? I would expect the code below // Test assigning user to group 2 to perform an update on the existing object, but instead DB::getQueryLog() only displays selects and inserts. This is really annoying.

-- Edit --

It's actually validation that's stopping me. I added a call to Model->errors() in the test above. This pointed out that after save, the username contained in the User object no longer was unique - because it found itself in the database (WTF?). It also said that the password_confirmation field was marked required, but was empty - because it was removed upon last save.

This is just stupid and I do not know if it is Eloquent, Ardent or me who's in fault here. If it was valid before save, it should be valid after save also - right? I will change the title of the question to reflect the real cause of the problem.

  • 写回答

1条回答 默认 最新

  • dpo60833 2014-01-07 13:29
    关注

    The only solution I've found to this problem, is to not use the 'unique' and 'confirmed' validation rules. I will handle validation for these upon form submission only.

    I'm actually not very happy with this solution, so I came up with a slightly different approach:

    // Validation rules for fields in this entity
    public static $rules = array(
        'username'              => 'required|alpha_dash|min:4|max:40',
        'password'              => 'required|alpha_dash|min:6|max:20',
        'password_confirmation' => ''
    );
    
    // Extra validation for user creation
    public static $onCreateRules = array(
        'username'              => 'required|alpha_dash|min:4|max:40|unique:users',
        'password'              => 'required|alpha_dash|min:6|max:20|confirmed'
    );
    

    Here I split the validation rules into two static arrays, and instead of extending the class from Ardent directly I extend it from a custom class:

    use LaravelBook\Ardent\Ardent;
    class ModelBase extends Ardent {
        public function save(array $rules = array(), array $customMessages = array(), array $options = array(), Closure $beforeSave = null, Closure $afterSave = null) {
            if (!$this->exists && isset(static::$onCreateRules)) {
                $rules = array_merge($rules, static::$onCreateRules);
            }
            return parent::save($rules, $customMessages, $options, $beforeSave, $afterSave);
        }
    }
    

    This overrides the Ardent save method and applies the $onCreateRules for validation ONLY if this entity does not previously exist. :-)

    I still think Eloquents validation engine is broken. A call to validate() should only validate dirty fields for one. Secondly it should automatically exclude the current entity id from a unique check. So in any case the solution I present here is a workaround.

    I hope someone from Laravel sees this and finds it in their heart to fix it.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 BV260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序