diff --git a/public/main/group/group.php b/public/main/group/group.php index af508babdc7..84b1571dbb8 100644 --- a/public/main/group/group.php +++ b/public/main/group/group.php @@ -236,7 +236,20 @@ if ('true' === api_get_setting('allow_group_categories')) { if (empty($categories)) { $defaultCategoryId = GroupManager::create_category( - get_lang('Default groups') + get_lang('Default groups'), + '', + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0 ); $defaultCategory = GroupManager::get_category($defaultCategoryId); $categories = [$defaultCategory]; @@ -267,6 +280,11 @@ href="group_category.php?'.api_get_cidreq().'&id='.$categoryId.'" title="'.get_lang('Edit').'">'. Display::getMdiIcon('pencil', 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Edit this category')).''; + // Add group + $actions .= ' '. + Display::getMdiIcon(ActionIcon::SUBSCRIBE_GROUP_USERS_TO_RESOURCE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Create new group(s)')).''; + // Delete $actions .= Display::url( Display::getMdiIcon(ActionIcon::DELETE, count($categories) == 1 ? 'ch-tool-icon-disabled' : 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')), diff --git a/public/main/group/group_category.php b/public/main/group/group_category.php index 9a2fe4d70b6..0fb889c2eb3 100644 --- a/public/main/group/group_category.php +++ b/public/main/group/group_category.php @@ -75,7 +75,7 @@ function check_groups_per_user($value) 'announcements_state' => GroupManager::TOOL_PRIVATE, 'forum_state' => GroupManager::TOOL_PRIVATE, 'max_student' => 0, - 'document_access' => 0, + 'document_access' => 0 ]; } @@ -452,6 +452,12 @@ function check_groups_per_user($value) $defaults['max_member_no_limit'] = 1; $defaults['max_member'] = $defaults['max_student']; } +/* +if (api_get_setting('allow_group_categories')) { + $defaults['id'] = $_GET['id']; +} +*/ + $form->setDefaults($defaults); $form->display(); diff --git a/public/main/group/group_creation.php b/public/main/group/group_creation.php index 4f57327fa74..8b67539b0d6 100644 --- a/public/main/group/group_creation.php +++ b/public/main/group/group_creation.php @@ -77,7 +77,18 @@ break; case 'create_class_groups': - GroupManager::create_class_groups($_POST['group_category']); + $classIds = []; + foreach (array_keys($_POST) as $key) { + if (strpos($key, 'checkbox_class_id_') !== false) { + $classId = str_replace('checkbox_class_id_', '', $key); + $classIds[] = (int)$classId; + } + } + if (isset($_POST['is_consistent_link'])) { + GroupManager::create_usergroup_consistent_groups($_POST['group_category'], $classIds); + } else { + GroupManager::create_class_groups($_POST['group_category'], $classIds); + } Display::addFlash(Display::return_message(get_lang('group(s) has (have) been added'))); header('Location: '.$currentUrl); exit; @@ -181,13 +192,17 @@ function copy_value(key) { $group_el = []; $group_el[] = $form->createElement('static', null, null, ' '); if ($allowGroupCategories) { - $group_el[] = $form->createElement( - 'checkbox', - 'same_category', - null, - get_lang('same for all'), - ['onclick' => "javascript: switch_state('category');"] - ); + if (!isset($_GET['category_id'])) { + $group_el[] = $form->createElement( + 'checkbox', + 'same_category', + null, + get_lang('same for all'), + ['onclick' => "javascript: switch_state('category');"] + ); + } else { + $group_el[] = $form->createElement('static', null, null, ' '); + } } $group_el[] = $form->createElement( 'checkbox', @@ -203,13 +218,29 @@ function copy_value(key) { $group_el = []; $group_el[] = $form->createElement('text', 'group_'.$group_number.'_name'); if ($allowGroupCategories) { - $group_el[] = $form->createElement( - 'select', - 'group_'.$group_number.'_category', - null, - $categories, - ['id' => 'category_'.$group_number] - ); + if(isset($_GET['category_id'])) { + $group_el[] = $form->createElement( + 'select', + 'group_' . $group_number . '_category', + null, + $categories, + [ + 'id' => 'category_' . $group_number, + 'disabled' => 'true', + 'style' => 'background-color: #f0f0f0;' + ] + ); + $group_el[] = $form->createElement('hidden', 'group_'.$group_number.'_category', $_GET['category_id']); + $defaults['group_'.$group_number.'_category'] = $_GET['category_id']; + } else { + $group_el[] = $form->createElement( + 'select', + 'group_' . $group_number . '_category', + null, + $categories, + ['id' => 'category_' . $group_number] + ); + } } else { $group_el[] = $form->createElement('hidden', 'group_'.$group_number.'_category', 0); @@ -247,7 +278,7 @@ function copy_value(key) { /* * Show form to generate new groups */ - $create_groups_form = new FormValidator('create_groups', 'post', api_get_self().'?'.api_get_cidreq()); + $create_groups_form = new FormValidator('create_groups', 'post', api_get_self().'?'.api_get_cidreq().(isset($_GET['category_id']) ? '&category_id='.$_GET['category_id'] : '')); $create_groups_form->addElement('header', $nameTools); $create_groups_form->addText('number_of_groups', get_lang('Number of groups to create'), null, ['value' => '1']); $create_groups_form->addButton('submit', get_lang('Proceed to create group(s)'), 'plus', 'primary'); @@ -306,16 +337,7 @@ function copy_value(key) { $obj = new UserGroupModel(); $classes = $obj->getUserGroupInCourse($options); if (count($classes) > 0) { - $description = '

'.get_lang('Using this option, you can create groups based on the classes subscribed to your course.').'

'; - $description .= ''; + $description = '

'.get_lang('Using this option, you can create groups based on the classes subscribed to your course.').'


'; $classForm = new FormValidator( 'create_class_groups_form', @@ -325,14 +347,42 @@ function copy_value(key) { $classForm->addHeader(get_lang('Groups from classes')); $classForm->addHtml($description); + + $classGroup = []; + + foreach ($classes as $index => $class) { + $number_of_users = count($obj->get_users_by_usergroup($class['id'])); + // $classForm->addCheckBox('checkbox_class_id_'.$class['id'], $class['title'] . ' ('.$number_of_users.' '.get_lang('Users').')'); + $classGroup[] = $classForm->createElement('checkbox', 'checkbox_class_id_'.$class['id'], null, $class['title'] . ' ('.$number_of_users.' '.get_lang('Users').')'); + } + + $classForm->addGroup( + $classGroup, + '', + null, + null, + false + ); + $classForm->addElement('hidden', 'action'); if ($allowGroupCategories) { - $classForm->addSelect('group_category', null, $categories); + if (isset($_GET['category_id'])) { + $classForm->addElement('hidden', 'group_category', $_GET['category_id']); + } else { + $classForm->addSelect('group_category', null, $categories); + } } else { $classForm->addElement('hidden', 'group_category'); } + + $classForm->addHtml('

'); + + $classForm->addCheckBox('is_consistent_link', null, get_lang('Link classes to created groups ?'), + ['title' => get_lang('Info message about deactivation of consistent link')] + ); + $classForm->addHtml('

'.get_lang('Info message about deactivation of consistent link').'

'); + $classForm->addButtonSave(get_lang('Validate')); - $defaults['group_category'] = GroupManager::DEFAULT_GROUP_CATEGORY; $defaults['action'] = 'create_class_groups'; $classForm->setDefaults($defaults); $classForm->display(); diff --git a/public/main/group/group_space.php b/public/main/group/group_space.php index d069f328ab3..05ace2cc822 100644 --- a/public/main/group/group_space.php +++ b/public/main/group/group_space.php @@ -141,6 +141,14 @@ class="btn btn--plain" href="'.api_get_self().'?selfUnReg=1" } } + // add edit tool + if (true) { + $actions_array[] = [ + 'url' => 'settings.php?'.api_get_cidreq(true, false).'&gid='.$group_id, + 'content' => Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('Edit')), + ]; + } + if (GroupManager::TOOL_NOT_AVAILABLE != $groupEntity->getDocState()) { $params = [ 'toolName' => 'document', diff --git a/public/main/group/member_settings.php b/public/main/group/member_settings.php index c916ef8ef18..c35135535a0 100644 --- a/public/main/group/member_settings.php +++ b/public/main/group/member_settings.php @@ -3,6 +3,9 @@ /* For licensing terms, see /license.txt */ require_once __DIR__.'/../inc/global.inc.php'; + +use Chamilo\CoreBundle\Framework\Container; + $this_section = SECTION_COURSES; $current_course_tool = TOOL_GROUP; @@ -14,7 +17,7 @@ $groupEntity = api_get_group_entity($group_id); $nameTools = get_lang('Edit this group'); -$interbreadcrumb[] = ['url' => 'group.php', 'name' => get_lang('Groups')]; +$interbreadcrumb[] = ['url' => 'group.php?'.api_get_cidreq(), 'name' => get_lang('Groups')]; $interbreadcrumb[] = ['url' => 'group_space.php?'.api_get_cidreq(), 'name' => $groupEntity->getTitle()]; $is_group_member = GroupManager::isTutorOfGroup(api_get_user_id(), $groupEntity); @@ -227,6 +230,25 @@ function check_group_members($value) $form->setDefaults($defaults); echo GroupManager::getSettingBar('member'); -$form->display(); + +// check if group has a CGroupRelUsergroup +$courseInfo = api_get_course_info_by_id(api_get_course_int_id()); + +if (GroupManager::is_group_linked_to_usergroup($groupEntity)) { + + echo '
Ce groupe est lié à la classe ' .$courseInfo['title'].'. La liste de ses membres dépend des membres de la classe et ne peut-être modifiée. + Allez dans les paramètres du groupe pour rompre ce lien si vous souhaitez ajouter ou ôter des membres de la classe. +
'; + + echo '

Membres du groupe

'; + $memberInfos = GroupManager::get_subscribed_users($groupEntity); + echo ''; +} else { + $form->display(); +} Display::display_footer(); diff --git a/public/main/group/settings.php b/public/main/group/settings.php index 8ca77e2660f..78264db0929 100644 --- a/public/main/group/settings.php +++ b/public/main/group/settings.php @@ -25,6 +25,13 @@ $groupRepo = Container::getGroupRepository(); /** @var CGroup $groupEntity */ $groupEntity = $groupRepo->find($group_id); +$linkedCategory = GroupManager::get_category_from_group($group_id); + +if (isset($_GET['remove_consistent_link'])) { + GroupManager::remove_group_consistent_link($groupEntity); + Display::addFlash(Display::return_message(get_lang('Group is no longer linked to the course'), 'normal')); + header('Location: group.php?'.api_get_cidreq(true, false)); +} if (null === $groupEntity) { api_not_allowed(true); @@ -35,9 +42,7 @@ $interbreadcrumb[] = ['url' => 'group_space.php?'.api_get_cidreq(), 'name' => $groupEntity->getTitle()]; $groupMember = GroupManager::isTutorOfGroup(api_get_user_id(), $groupEntity); -if (!$groupMember && !api_is_allowed_to_edit(false, true)) { - api_not_allowed(true); -} +$courseInfo = api_get_course_info_by_id(api_get_course_int_id()); // Build form $form = new FormValidator('group_edit', 'post', api_get_self().'?'.api_get_cidreq()); @@ -55,6 +60,17 @@ // Group name $form->addElement('text', 'name', get_lang('Group name')); +if (!$groupMember && !api_is_allowed_to_edit(false, true)) { + api_not_allowed(true); +} + +// Message for group rel usergroup +if (GroupManager::is_group_linked_to_usergroup($groupEntity)) { + $form->addHtml('
'.get_lang('Warning message to warn that the user cannot modify members of linked group').'
+ '.get_lang('Remove the group link with the class'). + '
'); +} + if ('true' === api_get_setting('allow_group_categories')) { $groupCategories = GroupManager::get_categories(); $categoryList = []; diff --git a/public/main/inc/lib/groupmanager.lib.php b/public/main/inc/lib/groupmanager.lib.php index 4c9f42c94f8..14370e05bde 100644 --- a/public/main/inc/lib/groupmanager.lib.php +++ b/public/main/inc/lib/groupmanager.lib.php @@ -11,6 +11,9 @@ use Doctrine\Common\Collections\Criteria; use Chamilo\CoreBundle\Component\Utils\ActionIcon; use Chamilo\CoreBundle\Component\Utils\ToolIcon; +use Chamilo\CourseBundle\Entity\CGroupRelUsergroup; +use Chamilo\CoreBundle\Entity\Usergroup; +use Chamilo\CoreBundle\Entity\Session; /** * This library contains some functions for group-management. @@ -386,11 +389,14 @@ public static function create_subgroups($group_id, $number_of_groups) /** * Create a group for every class subscribed to the current course. * + * @author Esteban Ristich + * * @param int $categoryId The category in which the groups should be created + * @param array $classIds The ids of the classes to be created * * @return array */ - public static function create_class_groups($categoryId) + public static function create_class_groups(int $categoryId, array $classIds = []): array { $options['where'] = [' usergroup.course_id = ? ' => api_get_course_int_id()]; $obj = new UserGroupModel(); @@ -398,23 +404,196 @@ public static function create_class_groups($categoryId) $group_ids = []; foreach ($classes as $class) { - $userList = $obj->get_users_by_usergroup($class['id']); + if (in_array((int)$class['id'], $classIds)) { + $userList = $obj->get_users_by_usergroup($class['id']); + $groupId = self::create_group( + $class['title'], + $categoryId, + 0, + null + ); + + if ($groupId) { + self::subscribeUsers($userList, api_get_group_entity($groupId)); + $group_ids[] = $groupId; + } + } + } + + return $group_ids; + } + + /** + * Create a group for every class subscribed to the current course + * + * @todo: move part of doctrine query in repository for future + * + * @author Esteban Ristich + * + * @param int $category_id The category in which the groups should be created + * @param array $classIds The ids of the classes to be created + * + * @return array + * @throws \Doctrine\DBAL\DBALException + */ + public static function create_usergroup_consistent_groups(int $category_id = 0, array $classIds = []): array + { + // check if group is not duplicated in same category + /** @var \Chamilo\CourseBundle\Repository\CGroupRelUsergroupRepository $relRepository */ + $relRepository = Database::getManager()->getRepository(CGroupRelUsergroup::class); + $filteredClassIds = $classIds; + + foreach ($classIds as $k => $classId) { + // get count of duclicated groups in same category + $qb = $relRepository->createQueryBuilder('gru'); + $qb = $qb->select('count(gru.id)'); + $qb = $qb->innerJoin('gru.group', 'g', \Doctrine\ORM\Query\Expr\Join::WITH, 'g.category = :categoryId'); + $qb->setParameter('categoryId', $category_id); + $qb->where($qb->expr()->eq('gru.usergroup', ':usergroupId')); + $qb->setParameter('usergroupId', $classId); + // $rawSQL = $qb->getQuery()->getSql(); + $groupNb = $qb->getQuery()->getSingleScalarResult(); + $isDuplicate = $groupNb !== 0; + if ($isDuplicate) { + unset($filteredClassIds[$k]); + } + } + + // check if a category has been done, create one otherwise + $categorieGroupe = self::get_category($category_id); + if (count($categorieGroupe) == 0) { + $category_id = self::create_category( + get_lang('DefaultGroupCategory'), + '', + 1, + 1, + 1, + 1, + 1, + 1 + ); + } + + if ($category_id == 0) { + return []; + } + + // BEGIN TEST + $courseId = api_get_course_int_id(); + $sessionId = api_get_session_id(); + $group_ids = []; + $session = Database::getManager()->getRepository(Session::class)->find($sessionId); + $course = Database::getManager()->getRepository(Course::class)->find($courseId); + + foreach ($filteredClassIds as $classId) { + $usergroup = Database::getManager()->getRepository(Usergroup::class)->find($classId); + $groupId = self::create_group( - $class['name'], - $categoryId, + $usergroup->getTitle(), // name of class (usergroup) + $category_id, // category_id 0, null ); + $group = Database::getManager()->getRepository(CGroup::class)->find($groupId); + + // fill the group from usergroup + $obj = new UserGroupModel(); + $userList = $obj->get_users_by_usergroup($classId); if ($groupId) { self::subscribeUsers($userList, api_get_group_entity($groupId)); - $group_ids[] = $groupId; } - } + $groupRelUsergroup = (new CGroupRelUsergroup()) + ->setGroup($group) + ->setUsergroup($usergroup) + ->setSession($session) + ->setCourse($course) + ->setReadyAutogroup(0) + ; + + $em = Database::getManager(); + $em->persist($groupRelUsergroup); + $em->flush(); + + $group_ids[] = $groupRelUsergroup->getId(); + } return $group_ids; } + /** + * Get the usergroup (class) linked to the group if it exists. + * + * @author Esteban Ristich + * + * @param CGroup $group + * + * @return Usergroup|null + */ + public static function get_usergroup_link(CGroup $group): ?Usergroup + { + $em = Database::getManager(); + $repo = $em->getRepository(CGroupRelUsergroup::class); + $criteria = [ + 'group' => $group, + ]; + + $rel = $repo->findOneBy($criteria); + if ($rel instanceof CGroupRelUsergroup) { + return $rel->getUsergroup(); + } else { + return null; + } + } + + /** + * Check if a group has a consistent link to an usergroup. + * + * @author Esteban Ristich + * + * @param CGroup $group + * + * @return bool + */ + public static function is_group_linked_to_usergroup(CGroup $group): bool + { + $em = Database::getManager(); + $repo = $em->getRepository(CGroupRelUsergroup::class); + $criteria = [ + 'group' => $group, + ]; + + $rel = $repo->findOneBy($criteria); + return $rel instanceof CGroupRelUsergroup; + } + + /** + * Remove the consistent link between usergroup and group. + * + * @author Esteban Ristich + * + * @param CGroup $group + * + * @return bool + */ + public static function remove_group_consistent_link(CGroup $group): bool + { + $em = Database::getManager(); + $repo = Database::getManager()->getRepository(CGroupRelUsergroup::class); + $criteria = [ + 'group' => $group, + ]; + + $rel = $repo->findOneBy($criteria); + if ($rel instanceof CGroupRelUsergroup) { + $em->remove($rel); + $em->flush(); + return true; + } else { + return false; + } + } + /** * Deletes groups and their data. * @@ -2236,6 +2415,12 @@ class = "btn btn--plain" } } + // linked class + if (api_get_setting('allow_group_categories') === 'true') { + $usergroup = GroupManager::get_usergroup_link($group); + isset($usergroup) ? $row[] = $usergroup->getTitle() : $row[] = '-'; + } + // @todo fix group session access. $groupSessionId = null; @@ -2317,6 +2502,9 @@ class = "btn btn--plain" $table->set_header($column++, get_lang('Groups')); $table->set_header($column++, get_lang('Group tutor')); $table->set_header($column++, get_lang('Registered'), false); + if (api_get_setting('allow_group_categories') === 'true') { + $table->set_header($column++, get_lang('Classe liée'), false); + } if (!api_is_allowed_to_edit(false, true)) { // If self-registration allowed diff --git a/src/CoreBundle/Framework/Container.php b/src/CoreBundle/Framework/Container.php index 82cd9649b1b..2bdffe14bcc 100644 --- a/src/CoreBundle/Framework/Container.php +++ b/src/CoreBundle/Framework/Container.php @@ -62,6 +62,7 @@ use Chamilo\CourseBundle\Repository\CForumThreadRepository; use Chamilo\CourseBundle\Repository\CGlossaryRepository; use Chamilo\CourseBundle\Repository\CGroupCategoryRepository; +use Chamilo\CourseBundle\Repository\CGroupRelUsergroupRepository; use Chamilo\CourseBundle\Repository\CGroupRepository; use Chamilo\CourseBundle\Repository\CLinkCategoryRepository; use Chamilo\CourseBundle\Repository\CLinkRepository; @@ -672,6 +673,11 @@ public static function getThemeHelper(): ThemeHelper return self::$container->get(ThemeHelper::class); } + public static function getGroupRelUsergroupRepository(): CGroupRelUsergroupRepository + { + return self::$container->get(CGroupRelUsergroupRepository::class); + } + public static function getAccessUrlHelper(): AccessUrlHelper { /** @var AccessUrlHelper $helper */ diff --git a/src/CourseBundle/Entity/CGroupRelUsergroup.php b/src/CourseBundle/Entity/CGroupRelUsergroup.php index 01505164551..45e98c6af2a 100644 --- a/src/CourseBundle/Entity/CGroupRelUsergroup.php +++ b/src/CourseBundle/Entity/CGroupRelUsergroup.php @@ -10,12 +10,13 @@ use Chamilo\CoreBundle\Entity\Session; use Chamilo\CoreBundle\Entity\Usergroup; use Doctrine\ORM\Mapping as ORM; +use Chamilo\CourseBundle\Repository\CGroupRelUsergroupRepository; /** * CGroupRelUsergroup. */ #[ORM\Table(name: 'c_group_rel_usergroup')] -#[ORM\Entity] +#[ORM\Entity(repositoryClass: CGroupRelUsergroupRepository::class)] class CGroupRelUsergroup { #[ORM\Id] @@ -55,7 +56,6 @@ public function getGroup(): CGroup public function setGroup(CGroup $group): self { $this->group = $group; - return $this; } @@ -67,7 +67,6 @@ public function getUsergroup(): Usergroup public function setUsergroup(Usergroup $usergroup): self { $this->usergroup = $usergroup; - return $this; } @@ -79,7 +78,6 @@ public function getSession(): ?Session public function setSession(?Session $session): self { $this->session = $session; - return $this; } @@ -91,7 +89,6 @@ public function getCourse(): ?Course public function setCourse(?Course $course): self { $this->course = $course; - return $this; } @@ -103,7 +100,6 @@ public function isReadyAutogroup(): bool public function setReadyAutogroup(bool $readyAutogroup): self { $this->readyAutogroup = $readyAutogroup; - return $this; } } diff --git a/src/CourseBundle/Repository/CGroupRelUsergroupRepository.php b/src/CourseBundle/Repository/CGroupRelUsergroupRepository.php new file mode 100644 index 00000000000..fb6aec2b0a3 --- /dev/null +++ b/src/CourseBundle/Repository/CGroupRelUsergroupRepository.php @@ -0,0 +1,15 @@ +