2 namespace wcf\system\importer
;
3 use wcf\data\user\group\UserGroup
;
4 use wcf\data\user\option\UserOption
;
5 use wcf\data\user\option\UserOptionList
;
6 use wcf\data\user\User
;
7 use wcf\data\user\UserEditor
;
8 use wcf\system\language\LanguageFactory
;
15 * @copyright 2001-2019 WoltLab GmbH
16 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
17 * @package WoltLabSuite\Core\System\Importer
19 class UserImporter
extends AbstractImporter
{
23 protected $className = User
::class;
26 * ids of default notification events
29 protected $eventIDs = [];
32 * list of user options
35 protected $userOptions = [];
37 const MERGE_MODE_EMAIL
= 4;
38 const MERGE_MODE_USERNAME_OR_EMAIL
= 5;
41 * Creates a new UserImporter object.
43 public function __construct() {
44 // get default notification events
45 $sql = "SELECT eventID
46 FROM wcf".WCF_N
."_user_notification_event
48 $statement = WCF
::getDB()->prepareStatement($sql);
49 $statement->execute([1]);
50 $this->eventIDs
= $statement->fetchAll(\PDO
::FETCH_COLUMN
);
52 $userOptionList = new UserOptionList();
53 $userOptionList->readObjects();
54 $this->userOptions
= $userOptionList->getObjects();
60 public function import($oldID, array $data, array $additionalData = []) {
63 // whether to perform a merge
64 $performMerge = false;
66 // fetch user with same username
67 $conflictingUser = User
::getUserByUsername($data['username']);
68 switch (ImportHandler
::getInstance()->getUserMergeMode()) {
69 /** @noinspection PhpMissingBreakStatementInspection */
70 case self
::MERGE_MODE_USERNAME_OR_EMAIL
:
71 // merge target will be the conflicting user
72 $targetUser = $conflictingUser;
74 // check whether user exists
75 if ($targetUser->userID
) {
79 case self
::MERGE_MODE_EMAIL
:
81 $targetUser = User
::getUserByEmail($data['email']);
82 // if it exists: perform a merge
83 if ($targetUser->userID
) $performMerge = true;
87 // merge should be performed
89 ImportHandler
::getInstance()->saveNewID('com.woltlab.wcf.user', $oldID, $targetUser->userID
);
93 // a conflict arose, but no merge was performed, resolve
94 if ($conflictingUser->userID
) {
96 $data['username'] = self
::resolveDuplicate($data['username']);
99 // check existing user id
100 if (ctype_digit((string)$oldID)) {
101 $user = new User($oldID);
102 if (!$user->userID
) $data['userID'] = $oldID;
105 // handle user options
107 if (isset($additionalData['options'])) {
108 foreach ($additionalData['options'] as $optionName => $optionValue) {
109 if (is_int($optionName)) $optionID = ImportHandler
::getInstance()->getNewID('com.woltlab.wcf.user.option', $optionName);
110 else $optionID = User
::getUserOptionID($optionName);
113 $userOptions[$optionID] = $optionValue;
118 foreach ($userOptions as $optionID => &$optionValue) {
119 switch ($this->userOptions
[$optionID]->optionType
) {
121 if ($optionValue) $optionValue = 1;
122 else $optionValue = 0;
126 $optionValue = intval($optionValue);
127 if ($optionValue > 2147483647) $optionValue = 2147483647;
131 $optionValue = floatval($optionValue);
135 if (strlen($optionValue) > 16777215) $optionValue = substr($optionValue, 0, 16777215);
140 if (!preg_match('/^\d{4}\-\d{2}\-\d{2}$/', $optionValue)) $optionValue = '0000-00-00';
144 if (strlen($optionValue) > 65535) $optionValue = substr($optionValue, 0, 65535);
150 if (isset($additionalData['languages'])) {
151 foreach ($additionalData['languages'] as $languageCode) {
152 $language = LanguageFactory
::getInstance()->getLanguageByCode($languageCode);
153 if ($language !== null) $languageIDs[] = $language->languageID
;
156 if (empty($languageIDs)) {
157 $languageIDs[] = LanguageFactory
::getInstance()->getDefaultLanguageID();
160 // assign an interface language
161 $data['languageID'] = reset($languageIDs);
164 $user = UserEditor
::create($data);
165 $userEditor = new UserEditor($user);
167 // updates user options
168 $userEditor->updateUserOptions($userOptions);
172 if (isset($additionalData['groupIDs'])) {
173 foreach ($additionalData['groupIDs'] as $oldGroupID) {
174 $newGroupID = ImportHandler
::getInstance()->getNewID('com.woltlab.wcf.user.group', $oldGroupID);
175 if ($newGroupID) $groupIDs[] = $newGroupID;
179 if (!$user->pendingActivation()) $defaultGroupIDs = UserGroup
::getGroupIDsByType([UserGroup
::EVERYONE
, UserGroup
::USERS
]);
180 else $defaultGroupIDs = UserGroup
::getGroupIDsByType([UserGroup
::EVERYONE
, UserGroup
::GUESTS
]);
182 $groupIDs = array_merge($groupIDs, $defaultGroupIDs);
183 $sql = "INSERT IGNORE INTO wcf".WCF_N
."_user_to_group
186 $statement = WCF
::getDB()->prepareStatement($sql);
187 WCF
::getDB()->beginTransaction();
188 foreach ($groupIDs as $groupID) {
189 $statement->execute([
194 WCF
::getDB()->commitTransaction();
197 $sql = "INSERT IGNORE INTO wcf".WCF_N
."_user_to_language
200 $statement = WCF
::getDB()->prepareStatement($sql);
201 foreach ($languageIDs as $languageID) {
202 $statement->execute([
208 // save default user events
209 $sql = "INSERT IGNORE INTO wcf".WCF_N
."_user_notification_event_to_user
212 $statement = WCF
::getDB()->prepareStatement($sql);
213 WCF
::getDB()->beginTransaction();
214 foreach ($this->eventIDs
as $eventID) {
215 $statement->execute([
220 WCF
::getDB()->commitTransaction();
223 ImportHandler
::getInstance()->saveNewID('com.woltlab.wcf.user', $oldID, $user->userID
);
225 return $user->userID
;
229 * Revolves duplicate user names and returns the new user name.
231 * @param string $username
234 private static function resolveDuplicate($username) {
238 $newUsername = 'Duplicate'.($i > 1 ?
$i : '').' '.$username;
240 $sql = "SELECT userID
241 FROM wcf".WCF_N
."_user
243 $statement = WCF
::getDB()->prepareStatement($sql);
244 $statement->execute([$newUsername]);
245 $row = $statement->fetchArray();
246 if (empty($row['userID'])) break;