/** * Import users * * This function is used to import users from the given CSV * file. * <br/>Example: * <code> * $file = new EfrontFile(/var/www/efront/upload/admin/temp/users.csv); * EfrontSystem :: importUsers($file); * </code> * * @param mixed $file The CVS file with the users, either an EfrontFile object or the full path to the file * @param boolean $replaceUsers Whether to replace existing users having the same name as the ones imported * @return array The imported users in an array of EfrontUser objects * @since 3.5.0 * @access public */ public static function importUsers($file, $replaceUsers = false) { if (!$file instanceof EfrontFile) { $file = new EfrontFile($file); } $usersTable = eF_getTableData("users", "*", ""); $tableFields = array_keys($usersTable[0]); // Get user types to check if they exist $userTypesTable = eF_getTableData("user_types", "*", ""); // Set the userTypesTable to find in O(1) the existence or not of a user-type according to its name foreach ($userTypesTable as $key => $userType) { $userTypesTable[$userType['name']] = $userType; } // If we work on the enterprise version we need to distinguish between users and module_hcd_employees tables fields //$userFields = array('login', 'password','email','languages_NAME','name','surname','active','comments','user_type','timestamp','avatar','pending','user_types_ID'); $userFields = eF_getTableFields('users'); $existingUsers = eF_getTableDataFlat("users", "login"); $fileContents = file_get_contents($file['path']); $fileContents = explode("\n", trim($fileContents)); $separator = ";"; //$fields = explode($separator, trim($fileContents[0])); $fields = str_getcsv(trim($fileContents[0]), $separator); if (sizeof($fields) == 1) { $separator = ","; //$fields = explode($separator, $fileContents[0]); $fields = str_getcsv(trim($fileContents[0]), $separator); if (sizeof($fields) == 1) { throw new Exception(_UNKNOWNSEPARATOR, EfrontSystemException::ILLEGAL_CSV); } } foreach ($fields as $key => $value) { if (empty($value)) { $unused = $key; unset($fields[$key]); } } $inserted = 0; $matched = array_intersect($fields, $tableFields); $newUsers = array(); $messages = array(); // The check here is removed to offer interoperability between enterprise and educational versions // throw new Exception (_PLEASECHECKYOURCSVFILEFORMAT, EfrontSystemException::ILLEGAL_CSV); for ($i = 1; $i < sizeof($fileContents); $i++) { //$csvUser = explode($separator, $fileContents[$i]); $csvUser = str_getcsv($fileContents[$i], $separator); unset($csvUser[$unused]); if (sizeof($csvUser) != sizeof($fields)) { throw new Exception(_PLEASECHECKYOURCSVFILEFORMAT . ': ' . _NUMBEROFFIELDSMUSTBE . ' ' . sizeof($fields) . ' ' . _BUTFOUND . ' ' . sizeof($csvUser), EfrontSystemException::ILLEGAL_CSV); } $csvUser = array_combine($fields, $csvUser); array_walk($csvUser, create_function('&$v, $k', '$v=trim($v);')); if (in_array($csvUser['login'], $existingUsers['login']) && $replaceUsers) { $existingUser = EfrontUserFactory::factory($csvUser['login']); $existingUser->delete(); } if (!in_array($csvUser['login'], $existingUsers['login']) || $replaceUsers) { if (!isset($csvUser['password']) || !$csvUser['password']) { $csvUser['password'] = $csvUser['login']; } // Check the user-type existence by name if ($csvUser['user_type_name'] != "" && isset($userTypesTable[$csvUser['user_type_name']])) { // If there is a mismatch between the imported custom type basic type and the current basic type // then set no custom type if ($userTypesTable[$csvUser['user_type_name']]['basic_user_type'] != $csvUser['user_type']) { $csvUser['user_types_ID'] = 0; } else { $csvUser['user_types_ID'] = $userTypesTable[$csvUser['user_type_name']]['id']; } } else { $csvUser['user_types_ID'] = 0; } unset($csvUser['user_type_name']); if (!$csvUser['user_type']) { $csvUser['user_type'] = 'student'; } //If user type is not valid, don't insert that user if ($csvUser['user_type'] != "administrator" && $csvUser['user_type'] != "professor" && $csvUser['user_type'] != "student") { $messages[] = '"' . $csvUser['login'] . '": ' . _INVALIDUSERTYPE; unset($csvUser); continue; } // If we are not in enterprise version then $csvEmployeeProperties is used as a buffer // This is done to enable enterprise <-> Enteprise, educational <-> educational, enterprise <-> educational imports/exports $csvEmployeeProperties = $csvUser; if (G_VERSIONTYPE == 'enterprise') { #cpp#ifdef ENTERPRISE // Copy all fields and remove the user ones -> leaving only employee related fields $csvEmployeeProperties['users_login'] = $csvUser['login']; } #cpp#endif // Delete and recreate $csvUser to keep only the fields in userFields unset($csvUser); foreach ($userFields as $field) { if (isset($csvEmployeeProperties[$field])) { $csvUser[$field] = $csvEmployeeProperties[$field]; if (G_VERSIONTYPE == 'enterprise') { #cpp#ifdef ENTERPRISE unset($csvEmployeeProperties[$field]); } #cpp#endif } } try { if (G_VERSIONTYPE == 'enterprise') { #cpp#ifdef ENTERPRISE $user = EfrontUser::createUser($csvUser); if (isset($csvEmployeeProperties['branch_name'])) { $result = eF_getTableData("module_hcd_branch", "branch_ID", "name='" . $csvEmployeeProperties['branch_name'] . "'"); if ($result[0]['branch_ID']) { $branchId = $result[0]['branch_ID']; } unset($csvEmployeeProperties['branch_name']); } if (isset($csvEmployeeProperties['job_name'])) { $result = eF_getTableData("module_hcd_job_description", "job_description_ID", "description='" . $csvEmployeeProperties['job_name'] . "'"); if ($result[0]['job_description_ID']) { $jobId = $result[0]['job_description_ID']; } unset($csvEmployeeProperties['job_name']); } if (isset($csvEmployeeProperties['job_role'])) { $csvEmployeeProperties['job_role'] ? $jobRole = 1 : ($jobRole = 0); unset($csvEmployeeProperties['job_role']); } $user->aspects['hcd'] = EfrontHcdUser::createUser($csvEmployeeProperties); if (isset($branchId) && isset($jobId) && isset($jobRole)) { $user->aspects['hcd']->addJob($user, $jobId, $branchId, $jobRole); } $newUsers[] = $user; } else { #cpp#else $newUsers[] = EfrontUser::createUser($csvUser); } #cpp#endif } catch (Exception $e) { $messages[] = '"' . $csvUser['login'] . '": ' . $e->getMessage() . ' (' . $e->getCode() . ')'; } } } return array($newUsers, $messages); }
/** * Construct content tree structure * * Creates a tree-like representation of the content, using arrays as EfrontUnit, * a class that extends ArrayObject. * Each unit is represented as an array with the appropriate fields * (id, name, timestamp etc). If the unit has children units, then * these are subarrays of the current unit array. All keys correspond * to unit ids. * If, for some reason, there are units with invalid succession data, * (parent or previous content ids), these are appended at the end of * the content tree. * <br/>Example: * <code> * $content = new EfrontContentTree(4); //Initialize content tree for lesson with id 4 * //Do some nasty stuff with content tree * $content -> reset(); //Reset content tree to its original state * </code> * * @since 3.5.0 * @access public */ public function reset() { if ($this->data) { $result = eF_getTableData("content", "*, data != '' as has_data", "lessons_ID = '" . $this->lessonId . "'"); } else { $fields = eF_getTableFields("content"); unset($fields[array_search('data', $fields)]); $result = eF_getTableData("content", implode(",", $fields) . ", data != '' as has_data", "lessons_ID = '" . $this->lessonId . "'"); } if (sizeof($result) == 0) { $this->tree = new RecursiveArrayIterator(array()); return; } $scorm2004Units = array(); $units = array(); foreach ($result as $unit) { $units[$unit['id']] = $unit; if (G_VERSIONTYPE != 'community') { #cpp#ifndef COMMUNITY if (G_VERSIONTYPE != 'standard') { #cpp#ifndef STANDARD if (in_array($unit['scorm_version'], EfrontContentTreeSCORM::$scorm2004Versions)) { $scorm2004Units[] = $unit['id']; } } #cpp#endif } #cpp#endif } if (!empty($scorm2004Units)) { $units = $this->convertUnitsTo2004($units, $scorm2004Units); } //$units = eF_getTableData("content", "id,name,parent_content_ID,lessons_ID,timestamp,ctg_type,active,previous_content_ID", "lessons_ID = '".$this -> lessonId."'"); $rejected = array(); foreach ($units as $node) { //Assign previous content ids as keys to the previousNodes array, which will be used for sorting afterwards if (!$this->data) { $node['has_data'] ? $node['data'] = 'efront#special#text' : ($node['data'] = ''); //Eliminate with 'efront#special#text' data for units that don't have any content, and set an empty space ' ' for units that have content. This is done so that the toHTML can handle differently the ones from the others. The efront#special#text is checked by persist() in order to leave data unchanged in case we are updating } $node = new EfrontUnit($node); //We convert arrays to array objects, which is best for manipulating data through iterators if (!isset($previousNodes[$node['previous_content_ID']])) { $previousNodes[$node['previous_content_ID']] = $node; } else { $rejected[$node['id']] = $node; //$rejected holds cut off units, which do not have a valid previous_content_ID } } $node = 0; $count = 0; $nodes = array(); //$count is used to prevent infinite loops while (sizeof($previousNodes) > 0 && isset($previousNodes[$node]) && $count++ < 10000) { //Order the nodes array according to previous_content_ID information. if $previousNodes[$node] is not set, it means that there are illegal previous content id entries in the array (for example, a unit reports as previous a non-existent unit). In this case, all the remaining units in the $previousNodes array are rejected $nodes[$previousNodes[$node]['id']] = $previousNodes[$node]; //Assign the previous node to be the array key $newNode = $previousNodes[$node]['id']; unset($previousNodes[$node]); $node = $newNode; } if (sizeof($previousNodes) > 0) { //If $previousNodes is not empty, it means there are invalid (orphan) units in the array, so append them to the $rejected list foreach ($previousNodes as $value) { $rejected[$value['id']] = $value; } } $tree = $nodes; $count = 0; //$count is used to prevent infinite loops while (sizeof($tree) > 1 && $count++ < 50000) { //We will merge all branches under the main tree branch, the 0 node, so its size will become 1 foreach ($nodes as $key => $value) { if ($value['parent_content_ID'] == 0 || in_array($value['parent_content_ID'], array_keys($nodes))) { //If the unit parent is in the $nodes array keys - which are the unit ids- or it is 0, then it is valid $parentNodes[$value['parent_content_ID']][] = $value; //Find which nodes have children and assign them to $parentNodes $tree[$value['parent_content_ID']][$value['id']] = array(); //We create the "slots" where the node's children will be inserted. This way, the ordering will not be lost } else { $rejected = $rejected + array($value['id'] => $value); //Append units with invalid parents to $rejected list unset($nodes[$key]); //Remove the invalid unit from the units array, as well as from the parentUnits, in case a n entry for it was created earlier unset($parentNodes[$value['parent_content_ID']]); } } if (isset($parentNodes)) { //If the unit was rejected, there won't be a $parentNodes array $leafNodes = array_diff(array_keys($nodes), array_keys($parentNodes)); //Now, it's easy to see which nodes are leaf nodes, just by subtracting $parentNodes from the whole set foreach ($leafNodes as $leaf) { $parent_id = $nodes[$leaf]['parent_content_ID']; //Get the leaf's parent $tree[$parent_id][$leaf] = $tree[$leaf]; //Append the leaf to its parent's tree branch unset($tree[$leaf]); //Remove the leaf from the main tree branch unset($nodes[$leaf]); //Remove the leaf from the nodes set } unset($parentNodes); //Reset $parentNodes; new ones will be calculated at the next loop } } if (sizeof($tree) > 0 && !isset($tree[0])) { //This is a special case, where only one node exists in the tree $tree = array($tree); } isset($tree[0]) ? $tree = $tree[0] : ($tree = array()); if (sizeof($rejected) > 0) { //Append rejected nodes to the end of the tree array, updating their parent/previous information foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($tree), RecursiveIteratorIterator::SELF_FIRST)) as $lastUnit) { } //Advance to the last tree node isset($lastUnit) ? $previousId = $lastUnit['id'] : ($previousId = 0); //There is a chance that no normal units exist in the tree. In this case, there will be no $lastUnit foreach ($rejected as $id => $node) { //Update broken nodes $node['parent_content_ID'] = 0; $node['previous_content_ID'] = $previousId; $node->persist(); //Persist changes to the database $tree[$id] = $node; $previousId = $id; } } $this->tree = new RecursiveArrayIterator($tree); //Create arrays for assigning the immediate children and the parents of each unit. These will come especially handy for SCORM 2004 calculations $this->immediateDescendants = array(); $this->nodeParents = array(); foreach (new EfrontNodeFilterIterator(new RecursiveIteratorIterator(new RecursiveArrayIterator($tree), RecursiveIteratorIterator::SELF_FIRST)) as $key => $value) { foreach (array_keys((array) $value) as $member) { !is_numeric($member) or $this->immediateDescendants[$key][] = $member; } if (isset($this->nodeParents[$value['parent_content_ID']]) && $this->nodeParents[$value['parent_content_ID']]) { $this->nodeParents[$key] = array_merge(array($value['parent_content_ID']), $this->nodeParents[$value['parent_content_ID']]); } else { $this->nodeParents[$key] = array($value['parent_content_ID']); } } //pr($this -> nodeParents); //pr($this -> immediateDescendants); }