fields['id'] = 0; $this->fields['nombre'] = 'All'; } else if (is_numeric($id_group) === true) { parent::__construct('tgrupo', ['id_grupo' => $id_group]); if ($recursive === true) { // Customize certain fields. $this->fields['parent'] = new Group($this->fields['parent']); } } else { // Empty skel. parent::__construct('tgrupo'); } } /** * Return an array of ids with all children * * @param boolean $ids_only Return an array of id_groups or * entire rows. * @param boolean $ignorePropagationState Search all children ignoring or * depending on propagate_acl flag. * * @return array With all children. */ public function getChildren( bool $ids_only=false, bool $ignorePropagationState=false ):array { $available_groups = \groups_get_children( $this->id_grupo(), $ignorePropagationState ); if (is_array($available_groups) === false) { return []; } if ($ids_only === true) { return array_keys($available_groups); } return $available_groups; } /** * Alias of 'nombre'. * * @param string|null $name Name of group. * * @return string|void Name assigned or void if set operation. */ public function name(?string $name=null) { if ($name === null) { return $this->nombre(); } return $this->nombre($name); } /** * Retrieves a list of groups fitered. * * @param array $filter Filters to be applied. * * @return array With all results or false if error. * @throws Exception On error. */ private static function search(array $filter):array { // Default values. if (empty($filter['id_user']) === true) { // By default query current user groups. $filter['id_user'] = false; } else if ((bool) \users_is_admin() === false) { // Override user queried if user is not an admin. $filter['id_user'] = false; } if (empty($filter['id_user']) === true) { $filter['id_user'] = false; } if (empty($filter['keys_field']) === true) { $filter['keys_field'] = 'id_grupo'; } if (isset($filter['returnAllColumns']) === false) { $filter['returnAllColumns'] = true; } $groups = \users_get_groups( $filter['id_user'], $filter['privilege'], $filter['returnAllGroup'], // Return all columns. $filter['returnAllColumns'], // Field id_groups is not being used anymore. null, $filter['keys_field'], // Cache. true, // Search term. $filter['search'] ); if (is_array($groups) === false) { return []; } return $groups; } /** * Returns an hierarchical ordered array. * * @param array $groups All groups available. * * @return array Groups ordered. */ private static function prepareGroups(array $groups):array { $return = []; $tree_groups = \groups_get_groups_tree_recursive($groups); foreach ($tree_groups as $k => $v) { $return[] = [ 'id' => $k, 'text' => \io_safe_output( \ui_print_truncate_text( $v['nombre'], GENERIC_SIZE_TEXT, false, true, false ) ), 'level' => $v['deep'], ]; } $unassigned = []; $processed = array_keys($tree_groups); foreach ($groups as $k => $v) { if (in_array($k, $processed) === true) { continue; } $unassigned[] = [ 'id' => $k, 'text' => \io_safe_output( \ui_print_truncate_text( $v, GENERIC_SIZE_TEXT, false, true, false ) ), 'level' => 0, ]; } return array_merge($unassigned, $return); } /** * Saves current group definition to database. * * @return mixed Affected rows of false in case of error. * @throws \Exception On error. */ public function save() { if (\is_management_allowed() !== true) { $msg = 'cannot be modified in a centralized management environment'; throw new \Exception( get_class($this).' error, '.$msg ); } $updates = $this->fields; if (is_numeric($updates['parent']) === false) { $updates['parent'] = $this->parent()->id_grupo(); } // Clean null fields. foreach ($updates as $k => $v) { if ($v === null) { unset($updates[$k]); } } if (isset($updates['propagate']) === false) { $updates['propagate'] = 0; } if (isset($updates['disabled']) === false) { $updates['disabled'] = 0; } if ($this->fields['id_grupo'] > 0) { return \db_process_sql_update( 'tgrupo', $updates, ['id_grupo' => $this->fields['id_grupo']] ); } else { // Create new group. $this->fields['id_grupo'] = \db_process_sql_insert( '\tgrupo', $updates ); if ($this->fields['id_grupo'] === false) { global $config; $msg = __( 'Failed to save group %s', $config['dbconnection']->error ); throw new \Exception( get_class($this).' error, '.$msg ); } else { return true; } } return false; } /** * Delete this group. * * @return void */ public function delete() { // Propagate parents. \db_process_sql_update( 'tgrupo', ['parent' => $this->parent()->id_grupo()], ['parent' => $this->id_grupo()] ); // Remove stats. \db_process_sql_delete( 'tgroup_stat', ['id_group' => $this->id_grupo()] ); // Remove group. \db_process_sql_delete( 'tgrupo', ['id_grupo' => $this->id_grupo()] ); unset($this->fields['id_grupo']); } /** * Return error message to target. * * @param string $msg Error message. * * @return void */ public static function error(string $msg) { echo json_encode(['error' => $msg]); } /** * Verifies target method is allowed to be called using AJAX call. * * @param string $method Method to be invoked via AJAX. * * @return boolean Available (true), or not (false). */ public static function ajaxMethod(string $method):bool { return in_array($method, self::$ajaxMethods) === true; } /** * This method is being invoked by select2 to improve performance while * installation has a lot of groups (more than 5k). * * Security applied in controller include/ajax/group.php. * * @return void * @throws \Exception On error. */ public static function getGroupsForSelect() { $id_user = get_parameter('id_user', false); $privilege = get_parameter('privilege', 'AR'); $returnAllGroup = get_parameter('returnAllGroup', false); $id_group = get_parameter('id_group', false); $keys_field = get_parameter('keys_field', 'id_grupo'); $search = get_parameter('search', ''); $step = get_parameter('step', 1); $limit = get_parameter('limit', false); $not_condition = get_parameter('not_condition', false); $exclusions = get_parameter('exclusions', '[]'); $inclusions = get_parameter('inclusions', '[]'); if (empty($id_user) === true) { $id_user = false; } $groups = self::search( [ 'id_user' => $id_user, 'privilege' => $privilege, 'returnAllGroup' => $returnAllGroup, 'returnAllColumns' => true, 'id_group' => $id_group, 'keys_field' => $keys_field, 'search' => $search, ] ); $exclusions = json_decode(\io_safe_output($exclusions), true); if (empty($exclusions) === false) { foreach ($exclusions as $ex) { unset($groups[$ex]); } } $inclusions = json_decode(\io_safe_output($inclusions), true); if (empty($inclusions) === false) { foreach ($inclusions as $k => $g) { if (empty($groups[$k]) === true) { if (is_numeric($g) === true) { $groups[$k] = \groups_get_name($k); } if (empty($groups[$k]) === true) { // Group does not exist, direct value assigned. $groups[$k] = $g; } } } } $return = self::prepareGroups($groups); // When not_condition is select firts option text change All to None. if ($not_condition === 'true') { $return[0]['text'] = 'None'; } if (is_array($return) === false) { return; } // Use global block size configuration. global $config; $limit = $config['block_size']; $offset = (($step - 1) * $limit); // Pagination over effective groups retrieved. // Calculation is faster than transference. $count = count($return); if (is_numeric($offset) === true && $offset >= 0) { if (is_numeric($limit) === true && $limit > 0) { $return = array_splice($return, $offset, $limit); } } if ($step > 2) { $processed = (($step - 2) * $limit); } else { $processed = 0; } $current_ammount = (count($return) + $processed); echo json_encode( [ 'results' => $return, 'pagination' => [ 'more' => $current_ammount < $count, ], ] ); } }