views:

1332

answers:

2

I've created an sfGuardUserProfile model that has a relation to the sfGuardUser model. Then I define another model with a relation to sfGuardUserProfile. I don't get any errors when I create the database, but when I try saving data to sfGuardUserProfile in my actions file, I get this error:

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

In my schema.yml, I am defining the relationships as one to one.

I'm not sure why this would be failing. Does Doctrine simply not support adding a new relationship to a model that already has a relationship?

Edit Here's my schema.yml:

sfGuardUserProfile:
  tableName: sf_guard_user_profile
  columns:
    sf_guard_user_id: { type: integer(4) }
    email:            { type: string(255) }
  relations:
    User:
      class:        sfGuardUser
      type:         one
      foreignType:  one
      onDelete:     CASCADE
      local:        sf_guard_user_id
      foreign:      id
      foreignAlias: Profile

FacebookAccount:
  tableName: facebook_account
  columns:
    user_id: { type: integer(4) }
    page_id: { type: integer }
  relations:
    sfGuardUserProfile:
      type:         one
      foreignType:  one
      class:        sfGuardUserProfile
      local:        user_id
      foreign:      sf_guard_user_id
      onDelete:     CASCADE
      foreignAlias: FacebookAccount

I encounter the error when I do this:

$profile = $this->getUser()->getProfile();
$profile->setEmail('[email protected]');
$profile->save();

The generated SQL:

INSERT INTO sf_guard_user_profile (sf_guard_user_id, email) VALUES (?, ?) - (1, [email protected])

The exact error:

SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`site`.`sf_guard_user_profile`, CONSTRAINT `sf_guard_user_profile_sf_guard_user_id_facebook_account_user_id` FOREIGN KEY (`sf_guard_user_id`) REFERENCES `facebook_account` (`user_id`))
+1  A: 

You have to ensure that you don't break database integrity: http://msdn.microsoft.com/en-us/library/ms175464.aspx . You can reach that inserting rows in correct order, for example:

$sfGuardUser = new sfGuardUser();
$sfGuardUser->id = 1;
$sfGuardUser->save();

$sfGuardUserProfile = new sfGuardUserProfile();
$sfGuardUserProfile->user_id = $sfGuardUser->id;
$sfGuardUserProfile->save();

or like this:

$sfGuardUser = new sfGuardUser();
$sfGuardUser->id = 1;

$sfGuardUserProfile = new sfGuardUserProfile();
$sfGuardUserProfile->User = $sfGuardUser;
sfGuardUserProfile->save();
Vladimir
Thanks for the response, Vladimir, but it looks like the constraint problem is between sfGuardUserProfile and FacebookAccount. And in this case I'm not even working with the FacebookAccount model, I'm only working with sfGuardUserProfile.
Arms
I did not read your update, when posted my answer. It does not matter that you dont work with the FacebookAccount, because you have FK sf_guard_user_profile.sf_guard_user_id -> facebook_account.user_id, so when you insert row in sf_guard_user_profile (sf_guard_user_id=1) you have to check, that there is a row in facebook_account with same user_id=1.
Vladimir
I tried creating a FacebookAccount model with user_id = 1 before working with sfGuardUserProfile, but I still get the error. It seems that I can't create either model, no matter which order I try.
Arms
+2  A: 

I think your problem is your FacebookAccount model not linking to the primary key on your Profile model and Doctrine not knowing how to work with it. Either change your FacebookAccount to reference the Profile primary key:

  relations:
    sfGuardUserProfile:
      type:         one
      foreignType:  one
      class:        sfGuardUserProfile
      local:        user_id
      foreign:      id
      onDelete:     CASCADE
      foreignAlias: FacebookAccount

or relate to the primary key of sfGuardUser:

  relations:
    sfGuardUser:
      type:         one
      foreignType:  one
      class:        sfGuardUser
      local:        user_id
      foreign:      id
      onDelete:     CASCADE
      foreignAlias: FacebookAccount
Cryo
I tried the first method, and got this error when creating the database:SQLSTATE[HY000]: general error: 1005 Can't create table 'site.#sql-cb0_1cb' (errno: 15). Failing Query: "ALTER TABLE facebook_account ADD CONSTRAINT facebook_account_user_id_sf_guard_user_profile_id FOREIGN KEY (user_id) REFERENCES sf_guard_user_profile(id) ON DELETE CASCADE". Failign Query: ALTER TABLE facebook_account ADD CONSTRAINT facebook_account_user_id_sf_guard_user_profile_id FOREIGN KEY (user_id) REFERENCES sf_guard_profile(id) ON DELETE CASCADE.
Arms
(I ran out of characters in the last comment...) and I can't really do the second method b/c $this->getUser()->FacebookAccount fails. I would actually prefer to do it this way, but I don't want to start hacking the sfDoctrineGuardUser classes.
Arms
For the first error I would suggest trying to drop your table and having Symfony create it from scratch if that's a possibility. For the second approach you would use $this->getUser()->getFacebookAccount() just in case that wasn't a typo (or $user = $this->getUser(); $user['FacebookAccount']...). The sfDoctrineGuardUser's core functionality is in it's base classes, feel free to modify the object in lib/model/doctrine/sfDoctrineGuardPlugin/sfGuardUser.class.php to suit your needs.
Cryo
Thanks for the responses, Cryo. I tried $this->getUser()->getFacebookAccount() but got this error: Call to undefined method myUser::getFacebookAccount. Unless you meant I had to edit the base class before this would work? (I wish I knew why this model behaved differently than other models that you can relate to.)
Arms
Sorry about that, you'll want to do $this->getUser()->getGuardUser()->getFacebookAccount().
Cryo
Nice, that did the trick. The getGuardUser() part makes sense. Thanks!
Arms
The reason you can do getProfile() off of the user is because the sfGuardPlugin adds a convenience method to skip the getGuardUser() call (see plugins/sfDoctrineGuardPlugin/lib/user/sfGuardSecurityUser.class.php). You can create your own convenience method for getFacebookProfile() in your app's user class in apps/{your app name}/lib/myUser.class.php to do the same.
Cryo
Ah, nice trick. Thanks for that bit of info.
Arms