2

1 対多の関係でオブジェクトを挿入する際に問題があります。これは私のコードです:

/** 
 * 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'
    );
}

PHP単体テスト

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
}

テスト実行は、ユーザー オブジェクトが更新されないことを反映します。なんで?私は何を間違っていますか?以下のコードは既存のオブジェクトの更新を実行することを期待しています// Test assigning user to group 2が、代わりにDB::getQueryLog()選択と挿入のみを表示します。これは本当に迷惑です。

- 編集 -

実際に私を止めているのは検証です。上記のテストで Model->errors() の呼び出しを追加しました。これは、保存後、User オブジェクトに含まれるユーザー名が一意ではなくなったことを示しています。また、password_confirmation フィールドは必須とマークされていましたが、最後の保存時に削除されたため、空でした。

これはばかげているだけで、ここで過ちを犯しているのはEloquentなのか、Ardentなのか、それとも私なのかわかりません。保存前に有効だった場合、保存後も有効なはずですよね?問題の本当の原因を反映するように質問のタイトルを変更します。

4

1 に答える 1

2

この問題に対して私が見つけた唯一の解決策は、「一意」および「確認済み」の検証規則を使用しないことです。フォームの送信時にのみ、これらの検証を処理します。

私は実際にはこのソリューションにあまり満足していないので、少し異なるアプローチを思いつきました:

// 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'
);

ここでは、検証ルールを 2 つの静的配列に分割し、クラスを Ardent から直接拡張する代わりに、カスタム クラスから拡張します。

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);
    }
}

これは Ardent save メソッドをオーバーライドし、このエンティティが以前に存在しない場合にのみ、検証のために $onCreateRules を適用します。:-)

Eloquents の検証エンジンが壊れていると思います。validate() への呼び出しは、1 つのダーティ フィールドのみを検証する必要があります。次に、現在のエンティティ ID を一意のチェックから自動的に除外する必要があります。いずれにせよ、ここで提示する解決策は回避策です。

Laravelの誰かがこれを見て、心の中でそれを見つけて修正してくれることを願っています.

于 2014-01-07T13:29:01.313 に答える