Skip to content
Snippets Groups Projects
suivi_unit.php 20.41 KiB
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
/**
 *
 * @package    format_iena
 * @copyright  2018 Softia/Université lorraine
 * @author     vrignaud camille / Thomas Fradet
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

define('NO_OUTPUT_BUFFERING', true);
require_once('../../../config.php');
//require_once('view/view_param_indicateur.php');
require_once('entity/course_format_iena_section_ressources.php');
require_once('entity/course_format_iena_sections.php');
require_once('entity/course_format_iena_groups.php');
require_once($CFG->dirroot.'/course/modlib.php');
use core_completion\cm_completion_details;
$PAGE->requires->css('/course/format/iena/styles.css');







global $COURSE, $DB, $USER, $PAGE;

function init_page($course) {
    global $PAGE;
    // Defines the id of the course with a get parameter.
    // Getting DB information (*)  of the course.

    $PAGE->set_title($course->fullname);
    $PAGE->set_heading($course->fullname . " – " .get_string('table_progress', 'format_iena'));
    $PAGE->set_pagelayout('incourse');

    // Cache le menu dans le header.
    $coursenode = $PAGE->navbar->add(get_string('table_progress', 'format_iena'),
        null, navigation_node::TYPE_CONTAINER, null, 'suiviena');
    $coursenode->make_active();
    $coursenode->force_open();

}

function get_groups($context, $activegroupids, $groups) {
    global $USER, $COURSE;
    // Groupe du GET provenant du sélecteur de la page du cours
    // ou premier groupe de l'utilisateur, ou groupe 0 (tous les groupes).
    $groupsall = new StdClass();
    // TODO à supprimer si pas utilisé dans le JS (mettre dans la clause IF pour éviter un appel inutile si le GET existe).
    $currentusergroupsids = groups_get_user_groups($COURSE->id, $USER->id)[0];
    $currentusergroups = [];
    $othergroups = [];

    // Groupes du cours avec id, nom et liste des id utilisateur de tous les
    // membres (3 clefs d'un tableau de groupes : id, name, member).

    $activegroupname = "";

    foreach ($groups as $group) {
        // Récupération des groupes dont fait partie l'utilisateur
        if (in_array($group->id, $currentusergroupsids)) {
            $currentusergroups[] = $group;
        } else {
            $othergroups[] = $group;
        }
    }


    $groupsall->othergroups = $othergroups;
    $groupsall->current_user_groups = $currentusergroups;
    return $groupsall;

}

// Formate l'achèvement d'activités pour le tableau de suivi. Pour chaque étudiant, on aura
// dans le bon ordre la liste des modules et le completionstate.
function format_progress($progress, $modules, $groups, $search=false, $activegroupids=0, $activesectionid=0) {

    global $CFG, $COURSE;
    $students = array();
    foreach ($progress as $proginfo) {

        $progressstudent = new StdClass();
        $progressstudent->firstname = $proginfo->firstname;
        $progressstudent->lastname = $proginfo->lastname;
        $progressstudent->id = $proginfo->id;
        $progressstudent->email = $proginfo->email;
        $progressstudent->progress = array();
        $progressstudent->report_link = $CFG->wwwroot . "/report/outline/user.php?id=" .
        $progressstudent->id . "&course=" . $COURSE->id . "&mode=outline";
        $progressstudent->message_link = $CFG->wwwroot . "/message/index.php?id=" . $progressstudent->id;
        $progressstudent->groups = "";
        $progressstudent->groupsid=array();
       
        if (!$search) {
            foreach ($groups as $group) {
                if (in_array($progressstudent->id, $group->members)) {
                    if(empty( $progressstudent->groups)){
                        $progressstudent->groups .= $group->name . "";
                    }
                    else{
                        $progressstudent->groups .= ", " .$group->name . " ";
                    }
                    array_push( $progressstudent->groupsid, $group->id);
                }
            }
        }
        else{
            $progressstudent->groups= $proginfo->groups;
            $progressstudent->groupsid= $proginfo->groupsid;
        }
        
        foreach ($modules as $key => $module) {
            $moduleprogress = new StdClass();

            if (!isset($proginfo->progress[$module->id])) {
                $moduleprogress->completionstate = '0';
            } else {
                $moduleprogress->completionstate = $proginfo->progress[$module->id]->completionstate;
            }
            $moduleprogress->namemodule = $module->name;
            $moduleprogress->idmodule = $module->id;

            $progressstudent->progress[$key] = $moduleprogress;
        }
        //error_log(print_r($progressstudent, true));
        $students[] = $progressstudent;
        
    }

    return $students;
}

function get_activities($completion, $activesectionid) {
    $activities = $completion->get_activities();
    $modules = [];
    foreach ($activities as $activity) {
        $module = new StdClass();
        $module->id = $activity->id;
        $module->name = $activity->name;
        $displayname = format_string($activity->name, true, array('context' => $activity->context));
        $module->displayname = strlen($displayname) > 50 ? mb_substr($displayname, 0, 49, 'UTF-8').'…' : $displayname;
        $module->section = $activity->section;
        if($activity->get_url()){
             $module->link=$activity->get_url()->out();
        }
       
        $modules[] = $module;
        if ($activity->section == $activesectionid || $activesectionid == 0 ) {
            $module->visible = true;
        } else {
            $module->visible = false;
        }

    }
    return $modules;
}

function get_sections($activesectionid) {
    global $COURSE;
    // Liste des sections du cours.
    $modinfo = get_fast_modinfo($COURSE->id);
    $sectionsinfoall = $modinfo->get_section_info_all();
    $sections = [];

    foreach ($sectionsinfoall as $key => $sectioninfo) {
        $section = new StdClass();
        $section->id = $sectioninfo->id;
        $section->name = $sectioninfo->name === null || $sectioninfo->name === '' ? 'Section ' . $key : $sectioninfo->name;
        if ($section->id == $activesectionid) {
            $section->selected = "selected";
        }

        $sections[] = $section;
    }
    return $sections;
}

function set_filters($data, $filters, $symbols, $sections, $currentusergroups, $othergroups, $activesectionid) {
    if (isset($_GET['filter'])) {
        $filtercomplete = $_GET['filter'];
        $symbols[mb_substr($filtercomplete, 0, 1, 'UTF-8')]->selected = "selected";
        $filters[mb_substr($filtercomplete, 1, null, 'UTF-8')]->selected = "selected";
    } else {
        $filters["0"]->selected = "selected";
        $symbols["≥"]->selected = "selected";
    }

    $data['filters'] = array_values($filters);
    $data['symbols'] = array_values($symbols);
    

   


    $data["sections"] = $sections;
    //Ici on récupère les groupes "autres" auxquels je n'appartiens pas
    //$data["groups"] = array_values($groups);
    $data["othergroups"]=$othergroups;
    $data['current_user_groups'] = $currentusergroups;

   
    $data['default_group'] = 'selected';
    $data['data'] = array();
    $data['data']["sections"] = $sections;
    //$data['data']["groups"] = array_values($groups);
    $data['data']['current_user_groups'] = $currentusergroups;
    $data['data']['active_section_id'] = $activesectionid;


    return $data;
}

//
function set_links($data, $modules,$listoptions) {
    global $COURSE, $USER, $CFG;

    $countmodules = count($modules);

    //$data["students"] = format_progress($progress, $modules, $groups, $activegroupsids, $activesectionid);
    //$countstudents = count($data["students"]);
    
    if ($countstudents > 0 && $countmodules > 0) {
        $data['count_results'] = $countstudents;
    }

    if (has_capability('course/iena:suivi_edit', $context = context_course::instance($COURSE->id), $USER->id)) {
        $data['link_bulkcompletion'] = $CFG->wwwroot . "/course/bulkcompletion.php?id=" . $COURSE->id;
    }

    $data['link_classicview'] = $CFG->wwwroot . "/report/progress/index.php?course=" . $COURSE->id;
    $data['link_editview']=$CFG->wwwroot . "/course/format/iena/suivi_edit.php?courseid=" . $COURSE->id;
    if($listoptions->listoptions['display_groups']["value"]){
        $data["display_groups"]=1;
    }
    if($listoptions->listoptions['display_details']["value"]){
        $data["display_details"]=1;
    }
    

    //$data['data'] = json_encode($data);
    return $data;
}

function get_progress_students($modules, $progress, $groups, $activegroupsids, $activesectionid, $courseid, $cache, $completion){
   

    //Si le progrès de chacun des groupes existe déjà en cache on va les charger, sinon on les récupère dans la BDD et on les stocke
    $arrayprogress=array();
    for($i=0; $i<count($activegroupsids); $i++){
        if($cache->get($courseid."-".$activegroupsids[$i]) !== false){
            error_log("on est passé dans le cache");
            $progress=$cache->get($courseid."-".$activegroupsids[$i]);
            
        }
        else{
            //On récupère le progrès des étudiants qui font partie des groupes activegroupsids
            $progressrequest = $completion->get_progress_all(
                '',
                array(),
                $activegroupsids[$i],
                'u.lastname ASC, u.firstname ASC',
                '',
                '',
                $context
            );  
            //On active le cache seulement s'il y a plus de x étudiants
            if($countstudents<1500){
                error_log("on set le cache");
                $cache->set($courseid."-".$activegroupsids[$i], $progressrequest);
            }
            $progress=$progressrequest;

        }

         $arrayprogress=(object) array_unique(array_merge((array) $arrayprogress, (array) $progress), SORT_REGULAR);
    }
        
        return format_progress($arrayprogress, $modules, $groups, false, $activegroupsids, $activesectionid);
}

function get_progress_student($identifier, $completion, $modules){
    global $DB;
    global $COURSE;
    $countmethod=0;
    $users=array();
    
    //Essayer de faire des switch case avec counttries
    $arrayparams=array();
    
    $explodedname=explode(" ", $identifier);
    $sql="SELECT DISTINCT u.id, u.firstname, u.lastname, u.email, u.idnumber
            FROM {user} u
            JOIN {user_enrolments} ue ON ue.userid = u.id
            JOIN {enrol} e ON e.id = ue.enrolid
            JOIN {role_assignments} ra ON ra.userid = u.id
            JOIN {context} ct ON ct.id = ra.contextid AND ct.contextlevel = 50
            JOIN {course} c ON c.id = ct.instanceid AND e.courseid = c.id
            JOIN {role} r ON r.id = ra.roleid AND r.shortname = 'student'
            WHERE e.status = 0 AND u.suspended = 0 AND u.deleted = 0 AND c.id= ?";
    $arrayparams[]=$COURSE->id;
    if(count($explodedname)>1){

        
        $sql.=" AND (u.lastname LIKE ? AND u.firstname LIKE ?) OR (u.lastname LIKE ? AND u.firstname LIKE ?)";
        
        array_push($arrayparams, $explodedname[0], $explodedname[1], $explodedname[1], $explodedname[0]);
    }
    else{
        $sql.=" AND u.lastname LIKE ? OR u.idnumber = ?";

        array_push($arrayparams, "".$identifier."%", $identifier);
    }


    $users=array_values($DB->get_records_sql($sql, $arrayparams));
    if(count($users)>0){

        $completion_student=array();
        $where = array();
        $where_params = array();
       
        //regarder get_in_or_equal
        for($i=0; $i<count($users);$i++){
       // foreach($users as $user){
            
            $where = $DB->sql_equal('u.id', ':idstudent', false, false);
            $where_params['idstudent'] = $users[$i]->id.'%';
            $completion_student=array_values($completion->get_progress_all($where, $where_params));
            $usergroup=groups_get_all_groups($COURSE->id, $users[$i]->id);
            $completion_student[0]->groups="";
            $completion_student[0]->groupsid=array();
            
            foreach($usergroup as $group){

                $completion_student[0]->groups.=$group->name;
                $completion_student[0]->groupsid[]=$group->id;
                
            }
            $arrayprogress=(object) array_unique(array_merge((array) $arrayprogress, (array) $completion_student), SORT_REGULAR);   
        }
        return format_progress($arrayprogress, $modules, false, true);

    }
    else{
        
        //On a pas trouvé d'utilisateur
        return array("error"=>"Pas d'utilisateurs trouvés");
    }
    

}

$filters = [
    "0" => (object)[
        "value" => "0",
        "name" => "0",
    ],
    "25" => (object)[
        "value" => "25",
        "name" => "25%",
    ],
    "50" => (object)[
        "value" => "50",
        "name" => "50%",
    ],
    "75" => (object)[
        "value" => "75",
        "name" => "75%",
    ],
    "100" => (object)[
        "value" => "100",
        "name" => "100%",
    ]
];

$symbols = [
    "=" => (object)[
        "value" => "=",
        "name" => "=",
    ],
    "<" => (object)[
        "value" => "<",
        "name" => "<",
    ],
    ">" => (object)[
        "value" => ">",
        "name" => ">",
    ],
    "≤" => (object)[
        "value" => "≤",
        "name" => "≤",
    ],
    "≥" => (object)[
        "value" => "≥",
        "name" => "≥",
    ]
];



//On s'occupe des options ici

$cache = cache::make('format_iena', 'students');
$courseid = required_param('courseid', PARAM_INT);
// Define the url of the view.
$url = new moodle_url('/course/format/iena/suivi_unit.php', array('courseid' => $courseid));
$PAGE->set_url($url);

$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
require_login($course);
require_once($CFG->libdir . '/completionlib.php');

$completion = new completion_info($course);
$context = context_course::instance($COURSE->id);


//On récupère les options du tableau de suivi : affichage du groupe, modale détails....
$listoptions=new \format_iena\output\course_format_iena_table_option();
$listoptions->setCourseid($courseid);
$listoptions->get_request_options();

if (!has_capability('course/iena:suivi', $context = context_course::instance($courseid), $USER->id)) {
    $link = $CFG->wwwroot . '/course/view.php?id=' . $courseid;
    header("Location: {$link}");
    exit;
}

$countstudents=count_enrolled_users($context);

//Si on a sélectionné des groupes dans les filtres
if (isset($_POST['groupsid'])) {
    
    $activegroupsids = $_POST['groupsid'];
} else {
    if($countstudents>1500){

        $activegroupsids = array();
    }
    else{
        $activegroupsids = array(0);
    }
    
}






$activesectionid = 0;
// Section du get acquise depuis le clic sur l'indicateur dans la page du cours,
// section depuis laquelle on a cliqué sur le bouton pour voir le suivi.
if (isset($_GET['sectionid'])) {
    $activesectionid = $_GET['sectionid'];
}

// On récupère les ids des membres parce que dans l'excel on veut savoir qui appartient à quel groupe.

$renderer = $PAGE->get_renderer('format_iena');


//Si on cherche les détails d'une activité
if (isset($_POST['action']) && $_POST['action'] == "details") {
    require_once($CFG->libdir . '/gradelib.php');
    $data = [];
    $idetu=$_POST['idetudiant'];
    $idmodule=$_POST['idmodule'];
    $modinfo = get_fast_modinfo($COURSE->id, $idetu);
    $cm = $modinfo->get_cm($idmodule);
    //Utile ?
    $completioninfo = new \completion_info($COURSE);
    $completiondetails = new cm_completion_details($completioninfo, $cm, $idetu);
    $activitydates = \core\activity_dates::get_dates_for_module($cm, $idetu);

    $activityinfo = new \core_course\output\activity_information($cm, $completiondetails, $activitydates);
    $activityhtml=$renderer->render_activity_information($activityinfo);
    $gradesobject=array();
    try{
        $gradesobject=grade_get_grades($COURSE->id, 'mod', $cm->modname, $cm->instance, $idetu);
    }
    catch(Exception $e){
        error_log($e);
    }
  
    $lastgrade=array();
    if(!empty($gradesobject) && !empty($gradesobject->items)){
        $lastgradeobject=end($gradesobject->items[0]->grades);
       
        if($lastgradeobject){
            $lastgrade["lastgrade"]=$lastgradeobject->str_long_grade;
            $lastgrade["datelastgrade"]=$lastgradeobject->dategraded;
        }

        if(isset($gradesobject->items[0]->gradepass)){
            $lastgrade["passgrade"]=number_format($gradesobject->items[0]->gradepass, 2, ',', ''); 
        }

        /*$lastgrade["passgrade"]=$gradesobject->items[0]->gradepass ? number_format($gradesobject->items[0]->gradepass, 2, ',', '') : null;*/
      
    }

    //en cas d'achèvement manuel on créé les petites pastilles vertes ou grises (terminé ou à faire)
    //

    $data =array();
    $data['url']=strval($cm->url);
    $data['completion']=strval($cm->completion);
    $data["grades"]=$lastgrade;
    $data["customcompletion"]=$cm->customdata;
    $data["completioninfos"]=$activityhtml;
    //Récupère le pourcentage de complétion total
    $data["completionstate"]=$completiondetails->get_overall_completion();
    $data["completiondetails"] = $completiondetails;
    $data["activityname"]=$cm->name;

  
    echo json_encode($data);
} 
else if(isset($_POST['action']) && $_POST['action'] == 'search_student' && isset($_POST['search_input'])){

    $data=[];
    $sanitized=filter_var($_POST['search_input'], FILTER_SANITIZE_STRING);
    $modules = get_activities($completion, $activesectionid);
    $data["modules"]=$modules;
    $data["students"]=get_progress_student($sanitized, $completion, $modules);
    //$data = set_links($data, $modules, $listoptions);
    echo json_encode($data);
}
// If a post is sent trought the page --> Si on change les filtres (de groupes), le template est appelé en JS
else if (isset($_POST['action']) && !empty($_POST['action'])) {

    $groups = groups_get_all_groups($COURSE->id, 0, 0, 'g.*', true);
    $data = [];
    $modules = get_activities($completion, $activesectionid);
    $data["students"]=get_progress_students($modules, $arrayprogress, $groups, $activegroupsids, $activesectionid, $courseid, $cache, $completion);
    $data["modules"]=$modules;
    $data["countstudents"]=$countstudents;

    $data["groups"]=$activegroupsids;
    $data["courseid"]=$courseid;
    //$data = set_links($data, $modules, $listoptions);
    echo json_encode($data);
} 

else {
    init_page($course, $PAGE);
    echo $OUTPUT->header();
    //$progress=$cache->get($activegroupids);
    $groups = groups_get_all_groups($COURSE->id, 0, 0, 'g.*', true);
    $data = [];
    //Si la complétion du cours n'est pas activée on redirige l'enseignant vers l'interface pour l'activer
    if(!$COURSE->enablecompletion){
        $data["completion_enabled"]=0;
        $data["link_enable"]= "<a href='".$CFG->wwwroot . '/course/edit.php?id=' . $courseid."'>sur ce lien</a>";
    }
    else{
        $data["completion_enabled"]=1;
        $currentusergroups = [];
        $activegroupname = "";

        

        $modules = get_activities($completion, $activesectionid);
        //Répartit les groupes en "mes groupes" et "les groupes dont je ne fais pas partie"
        $groupsall = get_groups($context, $activegroupsids, $groups);

        if (isset($groupsall->current_user_groups) && !empty($groupsall->current_user_groups)) {
            $currentusergroups = $groupsall->current_user_groups;
        }
        //$groups = $groupsall->groups;
        $sections = get_sections($activesectionid);
        //$data["countstudents"]=$countstudents;
        $data = set_links($data, $modules, $listoptions);
        $data = set_filters($data, $filters, $symbols, $sections,  $groupsall->current_user_groups, $groupsall->othergroups, $activesectionid);
        $data["groups"]=$activegroupsids;
        if (isset($_GET["msg_success"])) {
            $msg = $_GET["msg_success"];
            $data["msg_success"] = $msg;
        }


      
}
 
    $renderer->display_completion($data);
    echo $OUTPUT->footer();
}