Search code examples
yiiforeign-keysentity-relationship

Yii HAS_ONE relation doesn't save foreign key


I have a problem with HAS_ONE relation in Yii framework. The scenario is as follow: We have a User class with relation to SubscriptionType:

'subscriptionType' => array(self::HAS_ONE, 'SubscriptionType', 'subscription_type_id')

And s SubscriptioType with relation to User:

'users' => array(self::HAS_MANY, 'User', 'subscription_type_id')

What is more, User has a Foreign Key to SubscriptionType defined in the database.

There are 3 subscription types predefined and all the registering users get one of them by default during the registration. They are saved in the DB, so in the registerAction I do:

//some assignments here
$subscription = SubscriptionType::model()->find('name=:name', array(':name'=>SubscriptionType::MONTHLY));
$newUser->subscriptionType = $subscription;

if($newUser->save()){
    //redirect to some page
} else {
    Yii::trace('User register failed', 'application.controllers.UserController');
}

The user don't get saved. I debuged it bit and I noticed, that subscriptionType is assigned but subscription_type_id is not, so the INSERT query is throwing the constraint violation. Do I have to set the subscription_type_id explicitly? It doesnt make to much sense to me because it's against the idea of ORM, isnt' it?


Solution

  • I think you are defining the relations incorrectly. HAS_ONE is for the Parent side of a One-to-One relationship, and HAS_MANY is for the Parent side of a One-to-Many relationship. You need a BELONGS_TO on one of these which should be on the child side of the relationship. I am guessing that you user model should have the BELONGS_TO like this:

    'subscriptionType' => array(self::BELONGS_TO, 'SubscriptionType', 'subscription_type_id')
    

    The other issue you are having is that you are trying to assign a value to subscripionType when it is more like a read only attribute in that it is populated by the framework. In the case of a HAS_ONE, or a BELONGS_TO, this will be a CActiveRecord model. In the case of a HAS_MANY or MANY_TO_MANY, it will be an array of CActiveRecord models. These models are not saved when you save the parent model. However since they are indeed models, you can update and save these individual child models.