tags:

views:

597

answers:

1

I have a CakePHP model - User - that has ties to an external corporate system. I store some data on those systems and other data locally. In my User::beforeSave() method, I'm trying to set an ID, send the data (with that custom ID) to my corporate systems and then, if it inserts successfully there, return true so that Cake will insert the new user record with that same ID so that I can link them later.

I can't find a way to make this happen. Is there a way to insert a CakePHP record with a user-specified primary key value? I'm using UUIDs so there's (effectively) no opportunity for overlap.

$this->data['User']['id'] = String::uuid()

try {
   $user_proxy = new CoreServicesUserProxy();

   $corp_user = $user_proxy->CreateUser (

      array (

         'user' => array (

            'UserName'     => 'myusername',

            'EmailAddress' => $this->data['User']['email'],

            'SecurityId'   => $this->data['User']['id']

         )

      )

   );
}
catch ( Exception $e ) {
   // error handling stuff
   return false;
}
+1  A: 

I realise you have already been given some hints, but here is some code which might help.

Why not add an external_user_id field to your users table?

<?php
class User extends AppModel {

    function beforeSave() {
        $ds = ConnectionManager::getDataSource('core_services');
        $externalUser = $ds->createUser($this->data);
        if (!$externalUser) {
            return false;
        }
        $this->data['User']['external_id'] = $externalUser['id'];
        return true;
    }

    function afterFind($results, $primary) {
        // handle different types of find here ('all' vs 'first' vs through relation)
        foreach ($results as &$result) {
            $result = $this->_mergeExternalUser($result);
        }
    }

    function _mergeExternalUser($user) {
        $ds = ConnectionManager::getDataSource('core_services');
        $externalUser = $ds->retrieveUser($result['external_id']);
        return am($externalUser, $user);
    }

}
?>
deizel
Honestly, the only reason is economy of effort. My first choice is to do this in as laconic a manner as possible (no extra effort, entities, etc.). If that's not possible - and it appears that it isn't - then I'll adjust in the easiest way possible. In this case, by moving the API call to the afterSave() callback, I avoid having ot manage any additional data. Not my perfect world, but it will suffice. :-) Thanks.
Rob Wilkerson
This question has lingered long enough that I think it's fair to assume that it just isn't possible (in 1.2.x at least). I'm going to mark this as the answer since it's a solid workaround. What I actually did was reverse the calling order - local save first, remote save second. If the remote save fails, I rollback the local save.
Rob Wilkerson