1
votes

Comment déboguer un plugin personnalisé dans Moodle

On m'a demandé de créer un plugin personnalisé affichant un aperçu du cours (identifiant du cours, nom du cours, inscrit et terminé) via l'API. Il existe un plugin report_completionoverview auquel je peux me référer et que je souhaite essentiellement récupérer exactement la même liste via l'API Moodle au format JSON.

entrez la description de l'image ici

Je suis essayer de créer un plugin local basé sur la documentation de moodle ( https://docs.moodle.org/dev/Adding_a_web_service_to_a_plugin ) et d'autres plugins par défaut, mais ayant des difficultés à déboguer.

* nom du dossier modifié pour correspondre au nom du plugin *

J'ai créé

local / get_completion_overview / db / service.php

local / get_completion_overview / lang / en / local_get_completion_overview.php

local / get_completion_overview / externallib.php

local / get_completion_overview / version.php

Installation réussie du plugin sans erreur dans Moodle, mais le plugin n'est pas listé dans la fonction.

 Le plugin est installé

 entrez la description de l'image ici

Je pense honnêtement que mon le code n'est pas correct (et il est désordonné depuis que j'ai copié à partir de différentes sources), mais je ne sais pas comment le déboguer.

Quelqu'un peut-il me faire savoir si vous savez comment faire?

J'attache également local / completionview / externallib.php (je suis sûr que cela cause le problème que je crois). Toute aide, idée ou commentaire serait apprécié. Merci beaucoup!

<?php

$functions = array(
    'local_get_completion_overview' =>
        array('classname'   => 'local_get_completion_overview_external',
            'methodname'  => 'get_completion_overview',
            'classpath'   => 'local/get_completion_overview/externallib.php',
            'description' => 'Get course completion overview',
            'type'        => 'read',
            'capabilities'=> array(), //optional, useful to let the administrator know what potential capabilities the user 'could' need
            'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
        ),
    );

$services = array(
    'get completion overview' => array(                                                //the name of the web service
        'functions' => array ('local_get_completion_overview'), //web service functions of this service
        'requiredcapability' => '',                //if set, the web service user need this capability to access 
                                                                            //any function of this service. For example: 'some/capability:specified'                 
        'restrictedusers' =>0,                                             //if enabled, the Moodle administrator must link some user to this service
                                                                            //into the administration
        'enabled'=>1,                                                       //if enabled, the service can be reachable on a default installation
        )
);

** service.php

<?php
require_once($CFG->libdir . "/externallib.php");
require_once("lib.php");

class local_get_completion_overview_external extends external_api {

    public static function get_completion_overview_parameters() {
        return new external_function_parameters(
            array(
                'field' => new external_value(PARAM_ALPHA, 'The field to search can be left empty for all courses or:
                    id: course id
                    ids: comma separated course ids
                    shortname: course short name
                    idnumber: course id number
                    category: category id the course belongs to
                ', VALUE_DEFAULT, ''),
                'value' => new external_value(PARAM_RAW, 'The value to match', VALUE_DEFAULT, '')
            )
        );
    }

    public static function get_completion_overview($field = '', $value = ''){
        global $CFG, $DB;
        require_once($CFG->dirroot . '/course/lib.php');
        require_once($CFG->libdir . '/filterlib.php');

        $params = self::validate_parameters(self::get_completion_overview_parameters(),
            array(
                'field' => $field,
                'value' => $value,
            )
        );

        $sql = "SELECT DISTINCT cr.id AS courseid, cr.fullname AS coursename,
        COUNT(DISTINCT ra.id ) AS enrols,
        COUNT(DISTINCT cc.timecompleted) AS completed
        FROM {course} cr
        JOIN {context} ct ON ( ct.instanceid = cr.id )
        LEFT JOIN {role_assignments} ra ON ( ra.contextid = ct.id ) and ra.roleid = 5
        LEFT JOIN {course_completions} cc ON cc.course = cr.id
        GROUP BY  cr.fullname, cr.id
        ORDER BY coursename";

        $warnings = array();

        if (empty($params['field'])) {
            $courses = $DB->get_records_sql($sql, array());
        } else {
            switch ($params['field']) {
                case 'id':
                case 'category':
                    $value = clean_param($params['value'], PARAM_INT);
                    break;
                case 'ids':
                    $value = clean_param($params['value'], PARAM_SEQUENCE);
                    break;
                case 'shortname':
                    $value = clean_param($params['value'], PARAM_TEXT);
                    break;
                case 'idnumber':
                    $value = clean_param($params['value'], PARAM_RAW);
                    break;
                default:
                    throw new invalid_parameter_exception('Invalid field name');
            }

            if ($params['field'] === 'ids') {
                $courses = $DB->get_records_list('course', 'id', explode(',', $value), 'id ASC');
            } else {
                $courses = $DB->get_records('course', array($params['field'] => $value), 'id ASC');
            }
        }

        if(!empty($courses)){

            $coursesdata = array();
            $currentcourseid = null;
            $course = null;

            foreach($courses as $completion) {
                $context = context_course::instance($course->id);
                $crs = array();
                $crs['courseid'] = $completion->courseid;
                $crs['coursename'] = (string)$completion->coursename;
                $crs['enrols'] = $completion->enrols;
                $crs['completed'] = $completion->completed;

                try {
                    self::validate_context($context);
                } catch (Exception $e) {
                    continue;
                }

                if(is_null($currentcourseid) || ($completion->courseid != $currentcourseid)) {
                    if(!is_null($course)) {
                        $coursesdata[] = $course;
                    }
                    $course = array();
                    $course['courseid'] = $completion->courseid;
                }

                $course['courseid'][] = $crs;

                $currentcourseid = $completion->courseid;
            }

            if(!is_null($course)){
                $coursesdata[] = $course;
            }

            $courses->close();
        }

        $result = array();
        $result['course'] = $coursesdata;

        return $result;
    }

    public static function get_completion_overview_returns() {
        return new external_single_structure(
            array(
                'course' => new external_multiple_structure(self::get_completion_overview(), 'list of courses completion')
            )
            );
    }
}


3 commentaires

Juste en vérifiant, vous semblez avoir une lettre majuscule dans le nom de votre plugin répertorié ici - devrait-on dire local / completionview, au lieu de local / completionView (j'essaie de vérifier s'il s'agit d'une faute de frappe dans votre message ici, ou si vous avez vraiment mettre une lettre majuscule). Vous devez également publier le contenu de votre fichier service.php, car cela est essentiel à ce que vous faites ici.


@davosmith Merci pour votre réponse! J'ai corrigé le nom du dossier pour qu'il corresponde au nom du plugin et ajouté service.php


@davosmit Btw, j'ai réinstallé le plugin après avoir changé le nom du dossier et je n'ai eu aucune erreur. Plugin supprimé complètement - changé le nom - rafraîchir moodle - la mise à jour du plugin est venue automatiquement


3 Réponses :


0
votes

service.php doit être services.php. Après avoir corrigé le nom de fichier, il apparaît dans Moodle en tant que fonction, mais ayant un problème pour charger la fonction.

Propriété non définie: stdClass :: $ id in /Users/lucy/Sites/moodle/local/get_completion_overview/externallib.php en ligne 84

qui est

Stack trace:
line 1562 of /lib/dml/moodle_database.php: dml_missing_record_exception thrown
line 1538 of /lib/dml/moodle_database.php: call to moodle_database->get_record_select()
line 6822 of /lib/accesslib.php: call to moodle_database->get_record()
line 84 of /local/get_completion_overview/externallib.php: call to context_course::instance()
line 138 of /local/get_completion_overview/externallib.php: call to local_get_completion_overview_external::get_completion_overview()
line 124 of /lib/externallib.php: call to local_get_completion_overview_external::get_completion_overview_returns()
line 219 of /webservice/renderer.php: call to external_api::external_function_info()
line 121 of /admin/webservice/service_functions.php: call to core_webservice_renderer->admin_service_function_list()

dans chaque bloc.

aussi,

Informations de débogage: SELECT id, category FROM {course} WHERE id IS NULL [déployer ( )] Code d'erreur: enregistrement invalide

$context = context_course::instance($completion->id);


0 commentaires

0
votes

Incrémente le numéro de version dans le fichier version.php. Cela déclenchera moodle pour la mise à jour. Ensuite, vous devriez faire quelques mises à jour dans moodle. Après cela, vous devriez voir la liste


1 commentaires

Merci d'avoir répondu et désolé pour la réponse tardive. J'ai résolu le problème en changeant l'autorisation en has_capability ('moodle / site: config', $ context);



0
votes

Cela fonctionne comme prévu. J'ai changé l'autorisation en has_capability ('moodle / site: config', $ context); Je publie ma solution au cas où quelqu'un rencontrerait le même problème.

<?php
require_once('../../config.php');
require_once($CFG->libdir . "/externallib.php");
// require_once('../lib/externallib.php');
// require_once("lib.php");

class local_get_completion_overview_external extends external_api {

    public static function get_completion_overview_parameters() {
        return new external_function_parameters(
            array(
                'field' => new external_value(PARAM_ALPHA, 'The field to search can be left empty for all courses or:
                    id: course id', VALUE_DEFAULT, ''),
                'value' => new external_value(PARAM_RAW, 'The value to match', VALUE_DEFAULT, '')
            )
        );
    }

    public static function get_completion_overview($field='', $value=''){
        global $CFG, $DB;
        require_once($CFG->dirroot . '/course/lib.php');

        $params = self::validate_parameters(self::get_completion_overview_parameters(),
            array(
                'field' => $field,
                'value' => $value,
            )
        );

        $sql = "SELECT DISTINCT cr.id AS courseid,
                cr.fullname AS coursename,
                COUNT(DISTINCT ra.id ) AS enrols,
                COUNT(DISTINCT cc.timecompleted) AS completed
                FROM {course} cr
                JOIN {context} ct ON ( ct.instanceid = cr.id )
                LEFT JOIN {role_assignments} ra ON ( ra.contextid = ct.id ) and ra.roleid = 5
                LEFT JOIN {course_completions} cc ON cc.course = cr.id
                GROUP BY  cr.fullname, cr.id
                ORDER BY coursename";

        $warnings = array();
        $coursesdata = array();
        $requestedcourseids = $params['value'];

        if (empty($params['field'])) {
            $courses = $DB->get_records_sql($sql, array());
        } else {
            $value = clean_param($params['id'], PARAM_INT);

            if (count($value) > 0) {
                $placeholders = array();

                $sql_2 = "SELECT DISTINCT cr.id AS courseid, 
                            cr.fullname AS coursename, 
                            COUNT(DISTINCT ra.id) AS enrols, 
                            COUNT(DISTINCT cc.timecompleted) AS completed 
                            FROM {course} cr JOIN {context} ct ON ( ct.instanceid = cr.id ) 
                            LEFT JOIN {role_assignments} ra ON ( ra.contextid = ct.id ) and ra.roleid = 5 
                            LEFT JOIN {course_completions} cc ON (cc.course = cr.id) 
                            WHERE cr.id = ".$requestedcourseids." GROUP BY cr.fullname, cr.id";

                $courses = $DB->get_records_sql($sql_2, $placeholders);
            }
        }

        if(!empty($courses)) {
            $currentcourseid = null;
            $course = null;

            foreach($courses as $completion) {
                $context = context_system::instance();
                has_capability('moodle/site:config', $context);

                if(is_null($currentcourseid) || ($completion->courseid != $currentcourseid)) {
                    if(!is_null($course)) {
                        $coursesdata[] = $course;
                    }
                    $course = array();
                    $course['courseid'] = $completion->courseid;
                    $course['coursename'] = $completion->coursename;
                    $course['enrols'] = $completion->enrols;
                    $course['completed'] = $completion->completed;
                    $course['totalcourses'] = count($course);

                }

                $currentcourseid = $completion->courseid;
            }

            if(!is_null($course)){
                $coursesdata[] = $course;
            }

        } else {
            $warning = array();
            $warning['item'] = 'course';
            $warning['itemid'] = $requestedcourseids;
            $warning['warningcode'] = '1';
            $warning['message'] = 'No course found';

            $warnings[] = $warning;
        }

        $result['course'] = $coursesdata;
        $result['warnings'] = $warnings;

        return $result;
    }

    public static function get_completion_overview_returns() {
        return new external_single_structure(
            array(
                'course' => new external_multiple_structure(
                    new external_single_structure(
                        array(
                            'courseid' => new external_value(PARAM_INT, 'description'),
                            'coursename' => new external_value(PARAM_TEXT, ''),
                            'enrols' => new external_value(PARAM_INT, '', VALUE_OPTIONAL),
                            'completed' => new external_value(PARAM_INT, '', VALUE_OPTIONAL),
                            'totalcourses' => new external_value(PARAM_INT, '', VALUE_OPTIONAL),
                        )
                    )
                ),
                'warnings' => new external_warnings()
            )
        );
    }
}


0 commentaires