保存关系时强制“条件”

I'm using Laravel 4 for the first time to build a web application for a customer. I have two tables, User and Zone, with relationships between them.

In particular, this is (a simplified) User

Schema::create('users', function($table) {
    $table->increments('id');
    $table->string('name');
    $table->enum('role', array('type1', 'type2', 'type3')->default('type1');
    $table->integer('zone_id')->nullable();
});

and this is Zone

Schema::create('zones', function($table) {
    $table->increments('id');
    $table->string('name');
});

Users can have zero or one zones, this is why zone_id is nullable. However they can have one zone only if their role column has a value of type2 or type3, and not if role is type1.

These are my models

// models/User.php

class User extends Eloquent {

    public function zone() {
        return $this->belongsTo('Zone');
    }

}

// models/Zone.php

class Zone extends Eloquent {

    public function users() {
        return $this->hasMany('User');
    }

}

I don't know how to add the role condition in the models.

Indeed, I'm writing a test which fails:

class UserTest extends TestCase {

    public function testUserInZoneMustHaveASpecificRole() {
        $zone = FactoryMuff::create('Zone');
        $user = FactoryMuff::create('User');

        // $user, by default has role == 'type1'

        // This should pass, because I shouldn't be able to
        // associate a role=='type1' user to a zone

        $this->assertFalse($zone->users()->save($user)->save());
    }
}

Can you give me some help? I'm facing this problem in many parts of the application, due to my customer requests.

Thank you.

I would recommend that you check out "laravelbook/ardent"

https://github.com/laravelbook/ardent

This extension to the base Eloquent Model class does exactly what you want - it automatically validates before allowing a save.

Instead of manually calling validate(), you only call save() like this:

if ( $model->save() ) {
    echo "yay, it was all ok"
} else {
    echo "boo, we failed to save";
}

You create your validation rules in the same way as you would normally with Laravel, but Ardent is much smarter about handling them for you.