moodle_rest-1.0.1/src/Services/RestFunctions.php

src/Services/RestFunctions.php
<?php

namespace Drupal\moodle_rest\Services;

use Drupal\Core\Utility\Error;
use Psr\Log\LoggerInterface;

/**
 * Moodle Rest Functions Service.
 *
 * Adds helpers for Moodle Rest Webservice functions.
 * Helper methods should document the required parameters, and the returned
 * expected data, log warnings. Links to the moodle definitions included.
 * If you have access to the site you can also see a summary of all webservice
 * functions at '/admin/webservice/documentation.php'.
 */
class RestFunctions {

  /**
   * The Rest WS connector.
   *
   * @var \Drupal\moodle_rest\Services\MoodleRest
   */
  protected $rest;

  /**
   * The module logger channel.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * Static cache for repeat queries in the same call.
   *
   * @var []
   */
  protected static $cache = [];

  /**
   * Constructs a RestFunctions object.
   *
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.channel.moodle_rest service.
   */
  public function __construct(LoggerInterface $logger) {
    $this->logger = $logger;
  }

  /**
   * Set the Moodle Rest Webservice client.
   *
   * Otherwise default client from container will be used. Setting manually
   * allows overriding the configured Moodle server and token.
   */
  public function setRestClient(MoodleRest $rest) {
    self::$cache = [];
    $this->rest = $rest;
  }

  /**
   * Get the Moodle Rest Webservice client.
   */
  public function getRestClient() {
    if (empty($this->rest)) {
      $this->rest = \Drupal::service('moodle_rest.rest_ws');
    }
    return $this->rest;
  }

  /**
   * Core webservice.
   *
   * Moodle `core_webservice_*` functions.
   */

  /**
   * Get some site info / user info / list web service functions.
   *
   * Moodle function: core_webservice_get_site_info.
   *
   * @return array
   *   Array as defined by version of Moodle.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function getSiteInfo() {
    if (empty(self::$cache['site_info'])) {
      self::$cache['site_info'] = $this->getRestClient()->requestFunction('core_webservice_get_site_info');
    }

    return self::$cache['site_info'];
  }

  /**
   * Get Moodle Version.
   *
   * YYYYMMDD      = date of the 1.9 branch (don't change)
   *         X     = release number 1.9.[0,1,2,3,4,5...]
   *          Y.YY = micro-increments between releases.
   *
   * @return string
   *   Version number, or unknown if access to function denied, or error.
   */
  public function getSiteInfoVersion() {
    try {
      $site_info = $this->getSiteInfo();
    }
    catch (MoodleRestException $e) {
      if ($e->getCode() == 403 && $e->getBody()['errorcode'] = 'accessexception') {
        return 'unknown';
      }
      $this->logException($e);
      return 'error';
    }

    return $site_info['version'];
  }

  /**
   * Get Moodle Release.
   *
   * Human friendly form of version.
   *
   * @return string
   *   Release or unknown if access to function denied.
   */
  public function getSiteInfoRelease() {
    try {
      $site_info = $this->getSiteInfo();
    }
    catch (MoodleRestException $e) {
      if ($e->getCode() == 403 && $e->getBody()['errorcode'] = 'accessexception') {
        return 'unknown';
      }
      $this->logException($e);
      return 'error';
    }

    return $site_info['release'];
  }

  /**
   * Get Moodle Username.
   *
   * Name of user accessing the Webservice.
   *
   * @todo what is returned for anonymous access.
   *
   * @return string
   *   Username or '' on error including access denied to the function.
   */
  public function getSiteInfoUsername() {
    try {
      $site_info = $this->getSiteInfo();
    }
    catch (MoodleRestException $e) {
      if ($e->getCode() == 403 && $e->getBody()['errorcode'] = 'accessexception') {
        return '';
      }
      $this->logException($e);
      return '';
    }

    return $site_info['username'];
  }

  /**
   * Get Moodle Sitename.
   *
   * Name of user accessing the Webservice.
   *
   * @todo what is returned for anonymous access.
   *
   * @return string
   *   Username or '' on error including access denied to the function.
   */
  public function getSiteInfoSitename() {
    try {
      $site_info = $this->getSiteInfo();
    }
    catch (MoodleRestException $e) {
      if ($e->getCode() == 403 && $e->getBody()['errorcode'] = 'accessexception') {
        return '';
      }
      $this->logException($e);
      return '';
    }

    return $site_info['sitename'];
  }

  /**
   * Get Moodle Functions available.
   *
   * An array of the function currently available to the user of the webservice.
   *
   * @return array
   *   name => (string) Function name
   *   version => (string) The version number of the component to which the
   *   function belongs. Empty on error including access denied to the info
   *   function itself.
   */
  public function getSiteInfoFunctions() {
    try {
      $site_info = $this->getSiteInfo();
    }
    catch (MoodleRestException $e) {
      if ($e->getCode() == 403 && $e->getBody()['errorcode'] = 'accessexception') {
        return [];
      }
      $this->logException($e);
      return [];
    }

    return $site_info['functions'];
  }

  /**
   * Course webservice.
   *
   * Moodle `core_course_*` functions.
   *
   * @see https://github.com/moodle/moodle/blob/master/course/externallib.php
   */

  /**
   * Courses List.
   *
   * @param array $ids
   *   Optional. Array of course ids. If empty returns all courses except frontpage course.
   *   https://github.com/moodle/moodle/blob/master/course/externallib.php::get_courses_parameters().
   *
   * @return array
   *   Array of courses.
   *   https://github.com/moodle/moodle/blob/master/course/externallib.php::get_courses_returns().
   */
  public function getCourses(array $ids = []): array {
    if (empty($ids)) {
      return $this->getRestClient()->requestFunction('core_course_get_courses');
    }
    else {
      return $this->getRestClient()->requestFunction('core_course_get_courses', ['options' => ['ids' => $ids]]);
    }
  }

  /**
   * Course list by field.
   *
   * @param string $field
   *   Optional field to search by:
   *     'id': course id
   *     'ids': comma separated course ids
   *     'shortname': course short name
   *     'idnumber': course id number
   *     'category': category id the course belongs to.
   * @param string $value
   *   Used for 'value' => 'search_by'.
   *
   * @return array
   *   Array of courses.
   */
  public function getCoursesByField(string $field = '', string $value = ''): array {
    $options = [];
    if (!empty($field)) {
      $options = ['field' => $field, 'value' => $value];
    }
    $result = $this->getRestClient()->requestFunction('core_course_get_courses_by_field', $options);
    $this->logWarning($result);
    return $result['courses'];
  }

  /**
   * Create courses.
   *
   * core_course_external::create_courses_parameters()
   *
   * @param array $courses
   *   Required fields:
   *     'fullname': full name,
   *     'shortname': course short name,
   *     'categoryid' => category id,
   *   Optional fields:
   *     'idnumber': id number usual an external id,
   *     'summary': summary text,
   *     'summaryformat': summary format,
   *     'format': course format: weeks, topics, social, site,..,
   *     'showgrades': 1 if grades are shown, otherwise 0,
   *     'newsitems': number of recent items appearing on the course page,
   *     'startdate': timestamp when the course start,
   *     'enddate': timestamp when the course end,
   *     'numsections': (deprecated, use courseformatoptions) number of weeks/topics,
   *     'maxbytes': largest size of file that can be uploaded into the course,
   *     'showreports': are activity report shown (yes = 1, no =0)
   *     'visible': 1: available to student, 0:not available
   *     'hiddensections': (deprecated, use courseformatoptions) How the hidden sections in the course are displayed to students
   *     'groupmode': no group, separate, visible,
   *     'groupmodeforce': 1: yes, 0: no
   *     'defaultgroupingid': default grouping id
   *     'enablecompletion': Enabled, control via completion and activity settings. Disabled, not shown in activity settings.
   *     'completionnotify': 1: yes 0: no
   *     'lang': forced course language
   *     'forcetheme: name of the force theme
   *     'courseformatoptions': ['name' => 'option name', 'value' => 'option value']
   *     'additional options for particular course format': []
   *
   * @return array
   *   [ ['id' => Moodle Id, 'shortname' => course short name] ]
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   *   errorcatcontextnotvalid, errorinvalidparam.
   */
  public function createCourses(array $courses): array {
    $result = $this->getRestClient()->requestFunction('core_course_create_courses', ['courses' => $courses]);
    return $result;
  }

  /**
   * Update courses.
   *
   * @param array $courses
   *   Array of courses, as create. Id required, and fields to update.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function updateCourses(array $courses): void {
    $this->getRestClient()->requestFunction('core_course_update_courses', ['courses' => $courses]);
  }

  /**
   * Delete courses.
   *
   * @param int[] $course_ids
   *   Course IDs.
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function deleteCourses(array $course_ids): void {
    $this->getRestClient()->requestFunction('core_course_delete_courses', ['courseids' => $course_ids]);
  }

  /**
   * User webservice.
   *
   * Moodle `core_user_*` functions.
   *
   * @see https://github.com/moodle/moodle/blob/master/user/externallib.php
   */

  /**
   * Create Users.
   *
   * @param array $users
   *   Array of users. Required keys:
   *   - username string Username policy is defined in Moodle security config.
   *   - firstname string The first name(s) of the user.
   *   - lastname string The family name of the user.
   *   - email string A valid and unique email address.
   *   And one of:
   *   - createpassword int
   *     True if password should be created and mailed to user.
   *   - password string
   *     Plain text password consisting of any characters.
   *
   * @return array
   *   Array of [
   *     id int user id
   *     username string user name
   *   ].
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   *   Notably: Invalid parameter value detected. Including with message
   *   Invalid parameter value detected (Username already exists: username).
   */
  public function createUsers(array $users): array {
    $result = $this->getRestClient()->requestFunction('core_user_create_users', ['users' => $users]);
    return $result;
  }

  /**
   * Update users.
   *
   * @param array $users
   *   Array of users. Required key 'id', and fields to update.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function updateUsers(array $users): void {
    $this->getRestClient()->requestFunction('core_user_update_users', ['users' => $users]);
  }

  /**
   * Delete users.
   *
   * @param int[] $user_ids
   *   User IDs.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function deleteUsers(array $user_ids): void {
    $this->getRestClient()->requestFunction('core_user_delete_users', ['userids' => $user_ids]);
  }

  /**
   * Search users.
   *
   * @param array $criteria
   *   An array of search pairs ['field' => 'value'] to search.
   *   The search is executed with AND operator on the criterias.
   *   Invalid criterias (keys) are ignored.
   *
   * @return array
   *   Array of matching users.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function getUsers(array $criteria): array {
    $arguments = [];
    foreach ($criteria as $key => $value) {
      $arguments[] = [
        'key' => $key,
        'value' => $value,
      ];
    }
    $result = $this->getRestClient()->requestFunction('core_user_get_users', ['criteria' => $arguments]);
    $this->logWarning($result);
    return $result['users'];
  }

  /**
   * Get users by 'id', 'idnumber', 'username' or 'email'.
   *
   * Retrieve users' information for a specified unique field.
   * If you want to do a user search, use ::getUsers().
   *
   * @param string $field
   *   One of 'id' | 'idnumber' | 'username' | 'email'.
   * @param string[] $values
   *   Values to match.
   *
   * @return array
   *   Array of matching users.
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   */
  public function getUsersByField(string $field, array $values): array {
    return $this->getRestClient()->requestFunction('core_user_get_users_by_field', [
      'field' => $field,
      'values' => $values,
    ]);
  }

  /**
   * Enrol webservice.
   *
   * Moodle `core_enrol_*` functions.
   *
   * @see https://github.com/moodle/moodle/blob/master/enrol/externallib.php
   */

  /**
   * Get list of courses user is enrolled in.
   *
   * Only active enrolments are returned.
   * Please note the current user must be able to access the course,
   * otherwise the course is not included.
   *
   * @param int $moodle_id
   *   The user Moodle ID.
   * @param bool $return_user_count
   *   Include count of enrolled users for each course.
   *   This can add several seconds to the response time.
   *    Optional (default: false).
   *
   * @return array
   *   Courses.
   */
  public function getUsersCourses(int $moodle_id, bool $return_user_count = FALSE): array {
    $options = [
      'userid' => $moodle_id,
      'returnusercount' => $return_user_count,
    ];
    $result = $this->getRestClient()->requestFunction('core_enrol_get_users_courses', $options);
    return $result;
  }

  /**
   * Enrol manual webservice.
   *
   * Moodle `enrol_manual_*`` functions.
   *
   * @see https://github.com/moodle/moodle/blob/master/enrol/manual/externallib.php
   */

  /**
   * Enrol a single user on a single course.
   *
   * Creates the array and uses enrolUsersCourses().
   *
   * @param int $user_id
   *   The user Moodle ID.
   * @param int $course_id
   *   Moodle ID of the Course.
   * @param int $role_id
   *   The Moodle role ID.
   * @param int $timestart
   *   Optional.
   * @param int $timeend
   *   Optional.
   * @param bool $suspend
   *   Optional. True if suspended.
   */
  public function enrolUserCourse(int $user_id, int $course_id, int $role_id, ?int $timestart = NULL, ?int $timeend = NULL, ?bool $suspend = NULL): void {
    $enrolment = [
      'userid' => $user_id,
      'courseid' => $course_id,
      'roleid' => $role_id,
    ];
    if (!is_null($timestart)) {
      $enrolment['timestart'] = $timestart;
    }
    if (!is_null($timeend)) {
      $enrolment['timeend'] = $timeend;
    }
    if (!is_null($suspend)) {
      $enrolment['suspend'] = $suspend;
    }
    $this->enrolUsersCourses([$enrolment]);
  }

  /**
   * Enrol users to a courses.
   *
   * @param array $enrolments
   *   Keyed: userid, courseid, roleid required, and optional timestart, timend, suspend.
   *   See ::enrolUserCourse().
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   *   Ids `wsnoinstance` if there is no course, `wscannoctenrol` if it can't enrol.
   */
  public function enrolUsersCourses(array $enrolments): void {
    $this->getRestClient()->requestFunction('enrol_manual_enrol_users', ['enrolments' => $enrolments]);
  }

  /**
   * Enrol a single user on a single course.
   *
   * Creates the array and uses enrolUsersCourses().
   *
   * @param int $user_id
   *   The user Moodle ID.
   * @param int $course_id
   *   Moodle ID of the Course.
   * @param int $role_id
   *   The Moodle role ID.
   */
  public function unenrolUserCourse(int $user_id, int $course_id, int $role_id, ?int $timestart = NULL, ?int $timeend = NULL, ?bool $suspend = NULL): void {
    $enrolment = [
      'userid' => $user_id,
      'courseid' => $course_id,
      'roleid' => $role_id,
    ];
    $this->unenrolUsersCourses([$enrolment]);
  }

  /**
   * Unenrol users from courses.
   *
   * @param array $enrolments
   *   Keyed: userid, courseid, roleid.
   *   See ::unenrolUserCourse().
   *
   * @throws \Drupal\moodle_rest\Services\MoodleRestException
   *   Ids `wsnoinstance` if there is no course, `wscannoctunenrol` if it can't enrol.
   */
  public function unenrolUsersCourses(array $enrolments): void {
    $this->getRestClient()->requestFunction('enrol_manual_unenrol_users', ['enrolments' => $enrolments]);
  }

  /**
   * Completion webservice.
   *
   * Moodle `core_completion_*` functions.
   *
   * @see https://github.com/moodle/moodle/blob/master/completion/classes/external.php
   */

  /**
   * Get Course completion status.
   *
   * @param int $course_id
   *   Moodle ID of the Course.
   * @param int $user_id
   *   Moodle ID of the User.
   *
   * @return array
   *   Course completion status.
   *
   * @throws moodle_exception
   */
  public function getCourseCompletionStatus(int $course_id, int $user_id): array {
    $options = [
      'courseid' => $course_id,
      'userid' => $user_id,
    ];
    $result = $this->getRestClient()->requestFunction('core_completion_get_course_completion_status', $options);
    $this->logWarning($result);
    return $result['completionstatus'];
  }

  /**
   * Helper function to get course completion percentage.
   *
   * This combines retrieving _get_course_completion_status and
   * _activity_status. It will just return the % activies completed if
   * appropriate.
   *
   * @param int $course_id
   *   Moodle ID of the Course.
   * @param int $user_id
   *   Moodle ID of the User.
   *
   * @return int|null
   *   Percentage 0 - 100 or void if no criteria set or not enrolled.
   *
   * @throws moodle_exception
   */
  public function getCourseCompletionPercentage(int $course_id, int $user_id): ?int {
    $completion = [];
    try {
      $completion = $this->getCourseCompletionStatus($course_id, $user_id);
    }
    catch (MoodleRestException $e) {
      if (($moodle_error = $e->getBody()) && isset($moodle_error['errorcode']) && ($moodle_error['errorcode'] == 'nocriteriaset')) {
        return NULL;
      }
      else {
        throw $e;
      }
    }
    if ($completion['completed']) {
      return 100;
    }

    $activities = $this->getActivitiesCompletionStatus($course_id, $user_id);
    if (empty($activities)) {
      return NULL;
    }

    $completed_activities = array_filter($activities, function ($activity) {
      return (bool) $activity['timecompleted'];
    });
    return (int) round(count($completed_activities) / count($activities) * 100);
  }

  /**
   * Get Course activity completion status.
   *
   * @param int $course_id
   *   Moodle ID of the Course.
   * @param int $user_id
   *   Moodle ID of the User.
   *
   * @return array
   *   Course activity completion status.
   *
   * @throws moodle_exception
   */
  public function getActivitiesCompletionStatus(int $course_id, int $user_id): array {
    $options = [
      'courseid' => $course_id,
      'userid' => $user_id,
    ];
    $result = $this->getRestClient()->requestFunction('core_completion_get_activities_completion_status', $options);
    $this->logWarning($result);
    return $result['statuses'];
  }

  /**
   * Internal functions.
   */

  /**
   * Write an Moodle Rest Exception to the logger channel.
   *
   * Will include data from the Moodle response body as appropriate.
   */
  private function logException(MoodleRestException $e): void {
    $vars = Error::decodeException($e);
    $vars['@moodle'] = implode(', ', $e->getBody());
    $this->logger->error('%type: @message @moodle in %function (line %line of %file).', $vars);
  }

  /**
   * Log warnings.
   *
   * Moodle includes with some results an additional 'warnings' key value.
   */
  private function logWarning(array $results): void {
    if (!empty($results['warnings'])) {
      $backtrace = debug_backtrace(0, 2);
      foreach ($results['warnings'] as $warning) {
        $vars = [
          '@message' => print_r($warning, TRUE),
          '%function' => $backtrace[1]['function'],
          '%line' => $backtrace[1]['line'],
          '%file' => $backtrace[1]['file'],
        ];
      }
      $this->logger->warning('@message in %function (line %line of %file).', $vars);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc