3

So I successfully migrated users from a Joomla 3 database into a Joomla 4 database. I am hoping there is a nicer way if anyone has done it.

In particular, I couldn't work out how to create a user using the UserModel with a specific Id. Hence I had to set the user table autoincrement in the database to a high number to avoid collisions for when I set them back.

I get the impression that using the UserModel here is completely redundant and this would be better as a raw sql insert - but the question is... is there a good way to programmatically create users with known ids and password hashes.

$options = [
    'host'  => 'localhost',
    'database' => 'xxxxxxxxxxxx',
    'password' => 'xxxxxxxxxxxx',
    'user' => 'xxxxxxxxxxxxxxx',
    'prefix' => 'xxxxxx_',
];

// Connect to Old Joomla 3 Database

$odb = (new DatabaseFactory)->getDriver('mysqli', $options);
   
$query = $odb->getQuery(true);
$query->select('*');
$query->from('#__users');
$query->order('id');
$odb->setQuery($query);
$existing_users = $odb->loadAssocList('username');

$MvcFactory = $app->bootComponent('com_users')->getMVCFactory();

foreach($existing_users as $data){

    // Start everyone as Registered
    $data['groups'] = [2];

    unset($data["id"]);
    unset($data["lastResetTime"]);
    unset($data["resetCount"]);
    unset($data["otpKey"]);
    unset($data["otep"]);
    unset($data["requireReset"]);
    unset($data["authProvider"]);
    unset($data["params"]);

    // This needs to be an array so either json_decode old value or set blank
    $data["params"] = [];

    // empty date should be NULL in these times
    if($data["lastvisitDate"] == "0000-00-00 00:00:00"){
        unset($data["lastvisitDate"]);
    }

    $userModel = $MvcFactory->createModel('User', 'Administrator', ['ignore_request' => true]);

    // This will make a new id and hash the old hashed password
    if (!$userModel->save($data)){
        throw new Exception($userModel->getError());
    }
}

// Now Set all the Ids and Passwords back as they were
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$query->select('id,username');
$query->from('#__users');
$db->setQuery($query);
$users = $db->loadAssocList();

foreach($users as $u){

    // Skip any New Joomla 4 Users
    if(empty($existing_users[$u['username']])){continue;}

    $sql = 'UPDATE `#__users` SET `id` = ' . $existing_users[$u['username']]['id'] . ', `password` = "' . $existing_users[$u['username']]['password'] . '" WHERE `id` = ' . $u['id'];
    $sql2 = 'UPDATE `#__user_usergroup_map` SET `user_id` = ' . $existing_users[$u['username']]['id'] . ' WHERE `user_id` = ' . $u['id'];

    $db->setQuery($sql);
    $db->execute();
    $db->setQuery($sql2);
    $db->execute();

}
1
  • Since for this user migration the admin will use this script only one or max. few times, this script is good as it is (good help for anybody with the same problem) and this script does the job well as I see, does not require any Joomla optimization at the db query.
    – Zollie
    Commented Mar 9, 2023 at 9:28

1 Answer 1

0

The best option is to with a raw SQL insert - remember, this has to be done on 2 tables, the #__users table and the #__user_usergroup_map - it is also important to ensure that the IDs for the usergroups are the same, if not, then you will need to modify the SQL data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.