This forum is in READ-ONLY mode.
You can look around, but if you want to ask a new question, please use the new forum.
Home » plugins » User management plugins » Unable to $form->save() and setPassword() in one action
Unable to $form->save() and setPassword() in one action [message #100062] Sun, 30 May 2010 18:44 Go to next message
ShaneK  is currently offline ShaneK
Messages: 2
Registered: May 2010
Junior Member
Folks, I'm currently using Symfony [1.4.4] and the sfGuardDoctrinePlugin [4.0.1] to control access to an application I'm developing. I've also added a custom user profile table to hold various additional user information:

sfGuardUserProfile:
  connection: doctrine
  actAs: [Timestampable]
  columns:
    id:
      type: integer(4)
      primary: true
      autoincrement: true
    user_id:
      type: integer(4)
      unique: true
      notnull: true
    firstname:
      type: string(20)
      notnull: true
    lastname:
      type: string(20)
      notnull: true
    email:
      type: string(254}
    job_id:
      type: integer(4)
      notnull: true
  relations:
    User:
      class: sfGuardUser
      local: user_id
      foreign: id
      type: one
      foreignType: one
      foreignAlias: Profile
    Job:
      local: job_id
      foreign: id
      type: one


I then used Symfony to generate a Doctrine module with forms as a starter to allow me to create user profiles for existing users. This works fine.

In our system, users/profiles are created by the administrator - not by the end user - there isn't a user accessible registration process. Subsequently, I wanted to add functionality to the user profile module that would generate a random password, for the user who's profile was being created, and then send them an email with their login details. This is where is starts to go wrong.

Consider the following actions associated with the module:

 ...
 ...

 /**
  * Executes create action
  *
  * @param sfRequest $request A request object
  */
  public function executeCreate(sfWebRequest $request)
  {
    $this->forward404Unless($request->isMethod(sfRequest::POST));

    $this->form = new sfGuardUserProfileForm();

    $this->processForm($request, $this->form);

    $this->setTemplate('new');
  }

 ...
 ...

  protected function processForm(sfWebRequest $request, sfForm $form)
  {
    $form->bind($request->getParameter($form->getName()), $request->getFiles($form->getName()));
    if ($form->isValid())
    {
      $sf_guard_user_profile = $form->save();

      // Generate password and set it for user associated
      // with new user profile
      $password = myUtils::generatePassword();
      $sf_guard_user_profile->getUser()->setPassword($password);
      $sf_guard_user_profile->save();


      // Send email
      ...
      ...

      // Return to Employee Management
      $this->redirect('employee/manage');
    }
  }
 


However, attempting to set the password of the user associated with the user profile which has just been created fails with the following message:

500 | Internal Server Error | Doctrine_Connection_Mysql_Exception
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '3' for key 2


Looking at the Symfony Doctrine logs I can see why the problem is occurring, but I can't explain why Doctrine is doing it - here are the pertinent log messages:

19	 execute : INSERT INTO kaf_sf_guard_user_profile (user_id, firstname, lastname, email, job_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) - (3, Joe, Bloggs, joe@bloggs.com, 1, 2010-05-30 16:22:23, 2010-05-30 16:22:23)
22	 Doctrine_Connection_Statement	execute : UPDATE kaf_sf_guard_user SET password = ?, updated_at = ? WHERE id = ? - (<MD5 STRING OMITTED>, 2010-05-30 16:22:23, 3)
23	 Doctrine_Connection_Statement	execute : INSERT INTO kaf_sf_guard_user_profile (user_id, created_at, updated_at) VALUES (?, ?, ?) - (3, 2010-05-30 16:22:23, 2010-05-30 16:22:23)
24	 Doctrine_Connection_Mysql_Exception	SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '3' for key 2


So, first is the INSERT into the user profile table (kaf_sf_guard_user_profile) followed by an UPDATE to the kaf_sf_guard_user table to set the new password. However, what confuses me is that this is then followed up by an attempt to insert a new record into the user profile table - this time only including the user_id and timestampable fields.

If I remove the command to save the updated password:

$sf_guard_user_profile->save();
then the error disappears, but obviously the password for the user isn't updated. The logs show a new record being inserted into the user profile table, but no update to the user table.

So, as a little further testing I decided to create a new test action (PasswordTest) which I would use to simply update the password for the user of an existing profile like so:

  public function executePasswordTest(sfWebRequest $request)
  {
    $password = myUtils::generatePassword();
    $sf_guard_user_profile = Doctrine::getTable('sfGuardUserProfile')->find(array($request->getParameter('id')));
    $sf_guard_user_profile->getUser()->setPassword($password);
    $sf_guard_user_profile->save();

    $this->setTemplate('index');
  }


I then executed this action by passing in the ID of an existing user profile as part of the query string. This worked without any problem and the password of the underlying user was updated. Inspecting the symfony doctrine logs I could see that there was a single UPDATE to the user table.

So, the profile creation and password saving code appear to work fine in isolation - however bringing the two together seems to introduce an unwanted side effect whereby Doctrine wants to insert an additional row into the user profile table. Just wondering is this is a Symfony/Doctrine/sfGuard issue or whether its something to do with my code?

I've also attempted to set the new password by retrieving the user object straight from the DB rather than using the user profile object returned by form->save() as follows:

  protected function processForm(sfWebRequest $request, sfForm $form)
  {
    $form->bind($request->getParameter($form->getName()), $request->getFiles($form->getName()));
    if ($form->isValid())
    {
      $sf_guard_user_profile = $form->save();

      // Generate password and set it for user associated
      // with new user profile
      $password = myUtils::generatePassword();
      $sf_guard_user = Doctrine::getTable('sfGuardUser')->find($sf_guard_user_profile->getUser()->getId());
      $sf_guard_user->setPassword($password);
      $sf_guard_user->save();


      // Send email
      ...
      ...

      // Return to Employee Management
      $this->redirect('employee/manage');
    }
  }


Sadly, this approach led to the same end result. Any ideas?

[Updated on: Sun, 30 May 2010 18:49]

Re: Unable to $form->save() and setPassword() in one action [message #100163 is a reply to message #100062 ] Tue, 01 June 2010 12:02 Go to previous message
ShaneK  is currently offline ShaneK
Messages: 2
Registered: May 2010
Junior Member
In the meantime I have worked around this issue by splitting the conflicting code into two separate actions within the same module. After the user profile form is saved, I redirect to a new action which performs the password generation and update for the user record. Not ideal - but workable. I would still be curious to understand the reason for the behaviour that I have reported earlier if anyone could enlighten me. Thanks.
Previous Topic:After SignIn, Redirect to requested page (route), and not referrer
Next Topic:sfGuardLoginForm in layout.php
Goto Forum:
  

powered by FUDforum - copyright ©2001-2004 FUD Forum Bulletin Board Software