moodle/mod/data/classes/manager.php
Eloy Lafuente (stronk7) ba1f804ffa
MDL-65292 style: Fix all function declarations white space
This has been generated running the following Sniffs, all
them part of the Moodle's CodeSniffer standard:
- PSR12.Functions.ReturnTypeDeclaration
- PSR12.Functions.NullableTypeDeclaration
- moodle.Methods.MethodDeclarationSpacing
- Squiz.Whitespace.ScopeKeywordSpacing

All them are, exclusively, about correct spacing, so the changes
are, all them, only white space changes.

Only exceptions to the above are 3 changes what were setting the
return type in a new line, and, when that happens, the closing
parenthesis (bracket) has to go to the same line than the colon.
2024-02-28 23:33:26 +01:00

502 lines
16 KiB
PHP

<?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/>.
namespace mod_data;
use cm_info;
use context_module;
use completion_info;
use data_field_base;
use mod_data_renderer;
use mod_data\event\course_module_viewed;
use mod_data\event\template_viewed;
use mod_data\event\template_updated;
use moodle_page;
use core_component;
use stdClass;
/**
* Class manager for database activity
*
* @package mod_data
* @copyright 2022 Ferran Recio <ferran@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class manager {
/** Module name. */
const MODULE = 'data';
/** The plugin name. */
const PLUGINNAME = 'mod_data';
/** Template list with their files required to save the information of a preset. */
const TEMPLATES_LIST = [
'listtemplate' => 'listtemplate.html',
'singletemplate' => 'singletemplate.html',
'asearchtemplate' => 'asearchtemplate.html',
'addtemplate' => 'addtemplate.html',
'rsstemplate' => 'rsstemplate.html',
'csstemplate' => 'csstemplate.css',
'jstemplate' => 'jstemplate.js',
'listtemplateheader' => 'listtemplateheader.html',
'listtemplatefooter' => 'listtemplatefooter.html',
'rsstitletemplate' => 'rsstitletemplate.html',
];
/** @var string plugin path. */
public $path;
/** @var stdClass course_module record. */
private $instance;
/** @var context_module the current context. */
private $context;
/** @var cm_info course_modules record. */
private $cm;
/** @var array the current data_fields records.
* Do not access this attribute directly, use $this->get_field_records instead
*/
private $_fieldrecords = null;
/**
* Class constructor.
*
* @param cm_info $cm course module info object
* @param stdClass $instance activity instance object.
*/
public function __construct(cm_info $cm, stdClass $instance) {
global $CFG;
$this->cm = $cm;
$this->instance = $instance;
$this->context = context_module::instance($cm->id);
$this->instance->cmidnumber = $cm->idnumber;
$this->path = $CFG->dirroot . '/mod/' . self::MODULE;
}
/**
* Create a manager instance from an instance record.
*
* @param stdClass $instance an activity record
* @return manager
*/
public static function create_from_instance(stdClass $instance): self {
$cm = get_coursemodule_from_instance(self::MODULE, $instance->id);
// Ensure that $this->cm is a cm_info object.
$cm = cm_info::create($cm);
return new self($cm, $instance);
}
/**
* Create a manager instance from a course_modules record.
*
* @param stdClass|cm_info $cm an activity record
* @return manager
*/
public static function create_from_coursemodule($cm): self {
global $DB;
// Ensure that $this->cm is a cm_info object.
$cm = cm_info::create($cm);
$instance = $DB->get_record(self::MODULE, ['id' => $cm->instance], '*', MUST_EXIST);
return new self($cm, $instance);
}
/**
* Create a manager instance from a data_record entry.
*
* @param stdClass $record the data_record record
* @return manager
*/
public static function create_from_data_record($record): self {
global $DB;
$instance = $DB->get_record(self::MODULE, ['id' => $record->dataid], '*', MUST_EXIST);
$cm = get_coursemodule_from_instance(self::MODULE, $instance->id);
$cm = cm_info::create($cm);
return new self($cm, $instance);
}
/**
* Return the current context.
*
* @return context_module
*/
public function get_context(): context_module {
return $this->context;
}
/**
* Return the current instance.
*
* @return stdClass the instance record
*/
public function get_instance(): stdClass {
return $this->instance;
}
/**
* Return the current cm_info.
*
* @return cm_info the course module
*/
public function get_coursemodule(): cm_info {
return $this->cm;
}
/**
* Return the current module renderer.
*
* @param moodle_page|null $page the current page
* @return mod_data_renderer the module renderer
*/
public function get_renderer(?moodle_page $page = null): mod_data_renderer {
global $PAGE;
$page = $page ?? $PAGE;
return $page->get_renderer(self::PLUGINNAME);
}
/**
* Trigger module viewed event and set the module viewed for completion.
*
* @param stdClass $course course object
*/
public function set_module_viewed(stdClass $course) {
global $CFG;
require_once($CFG->libdir . '/completionlib.php');
// Trigger module viewed event.
$event = course_module_viewed::create([
'objectid' => $this->instance->id,
'context' => $this->context,
]);
$event->add_record_snapshot('course', $course);
$event->add_record_snapshot('course_modules', $this->cm);
$event->add_record_snapshot(self::MODULE, $this->instance);
$event->trigger();
// Completion.
$completion = new completion_info($course);
$completion->set_module_viewed($this->cm);
}
/**
* Trigger module template viewed event.
*/
public function set_template_viewed() {
// Trigger an event for viewing templates.
$event = template_viewed::create([
'context' => $this->context,
'courseid' => $this->cm->course,
'other' => [
'dataid' => $this->instance->id,
],
]);
$event->add_record_snapshot(self::MODULE, $this->instance);
$event->trigger();
}
/**
* Return if the database has records.
*
* @return bool true if the database has records
*/
public function has_records(): bool {
global $DB;
return $DB->record_exists('data_records', ['dataid' => $this->instance->id]);
}
/**
* Return if the database has fields.
*
* @return bool true if the database has fields
*/
public function has_fields(): bool {
global $DB;
if ($this->_fieldrecords === null) {
return $DB->record_exists('data_fields', ['dataid' => $this->instance->id]);
}
return !empty($this->_fieldrecords);
}
/**
* Return the database fields.
*
* @return data_field_base[] the field instances.
*/
public function get_fields(): array {
$result = [];
$fieldrecords = $this->get_field_records();
foreach ($fieldrecords as $fieldrecord) {
$result[$fieldrecord->id] = $this->get_field($fieldrecord);
}
return $result;
}
/**
* Return the field records (the current data_fields records).
*
* @return stdClass[] an array of records
*/
public function get_field_records() {
global $DB;
if ($this->_fieldrecords === null) {
$this->_fieldrecords = $DB->get_records('data_fields', ['dataid' => $this->instance->id], 'id');
}
return $this->_fieldrecords;
}
/**
* Return a specific field instance from a field record.
*
* @param stdClass $fieldrecord the fieldrecord to convert
* @return data_field_base the data field class instance
*/
public function get_field(stdClass $fieldrecord): data_field_base {
global $CFG; // Some old field plugins require $CFG to be in the scope.
$filepath = "{$this->path}/field/{$fieldrecord->type}/field.class.php";
$classname = "data_field_{$fieldrecord->type}";
if (!file_exists($filepath)) {
return new data_field_base($fieldrecord, $this->instance, $this->cm);
}
require_once($filepath);
if (!class_exists($classname)) {
return new data_field_base($fieldrecord, $this->instance, $this->cm);
}
$newfield = new $classname($fieldrecord, $this->instance, $this->cm);
return $newfield;
}
/**
* Return a specific template.
*
* NOTE: this method returns a default template if the module template is empty.
* However, it won't update the template database field.
*
* Some possible options:
* - search: string with the current searching text.
* - page: integer repesenting the current pagination page numbre (if any)
* - baseurl: a moodle_url object to the current page.
*
* @param string $templatename
* @param array $options extra display options array
* @return template the template instance
*/
public function get_template(string $templatename, array $options = []): template {
if ($templatename === 'single') {
$templatename = 'singletemplate';
}
$instance = $this->instance;
$templatecontent = $instance->{$templatename} ?? '';
if (empty($templatecontent)) {
$templatecontent = data_generate_default_template($instance, $templatename, 0, false, false);
}
$options['templatename'] = $templatename;
// Some templates have extra options.
$options = array_merge($options, template::get_default_display_options($templatename));
return new template($this, $templatecontent, $options);
}
/** Check if the user can manage templates on the current context.
*
* @param int $userid the user id to check ($USER->id if null).
* @return bool if the user can manage templates on current context.
*/
public function can_manage_templates(?int $userid = null): bool {
global $USER;
if (!$userid) {
$userid = $USER->id;
}
return has_capability('mod/data:managetemplates', $this->context, $userid);
}
/** Check if the user can export entries on the current context.
*
* @param int $userid the user id to check ($USER->id if null).
* @return bool if the user can export entries on current context.
*/
public function can_export_entries(?int $userid = null): bool {
global $USER, $DB;
if (!$userid) {
$userid = $USER->id;
}
// Exportallentries and exportentry are basically the same capability.
return has_capability('mod/data:exportallentries', $this->context) ||
has_capability('mod/data:exportentry', $this->context) ||
(has_capability('mod/data:exportownentry', $this->context) &&
$DB->record_exists('data_records', ['userid' => $userid, 'dataid' => $this->instance->id]));
}
/**
* Update the database templates.
*
* @param stdClass $newtemplates an object with all the new templates
* @return bool if updated successfully.
*/
public function update_templates(stdClass $newtemplates): bool {
global $DB;
$record = (object)[
'id' => $this->instance->id,
];
foreach (self::TEMPLATES_LIST as $templatename => $templatefile) {
if (!isset($newtemplates->{$templatename})) {
continue;
}
$record->{$templatename} = $newtemplates->{$templatename};
}
// The add entry form cannot repeat tags.
if (isset($record->addtemplate) && !data_tags_check($this->instance->id, $record->addtemplate)) {
return false;
}
$DB->update_record(self::MODULE, $record);
$this->instance = $DB->get_record(self::MODULE, ['id' => $this->cm->instance], '*', MUST_EXIST);
// Trigger an event for saving the templates.
$event = template_updated::create(array(
'context' => $this->context,
'courseid' => $this->cm->course,
'other' => array(
'dataid' => $this->instance->id,
)
));
$event->trigger();
return true;
}
/**
* Reset all templates.
*
* @return bool if the reset is done or not
*/
public function reset_all_templates(): bool {
$newtemplates = new stdClass();
foreach (self::TEMPLATES_LIST as $templatename => $templatefile) {
$newtemplates->{$templatename} = '';
}
return $this->update_templates($newtemplates);
}
/**
* Reset all templates related to a specific template.
*
* @param string $templatename the template name
* @return bool if the reset is done or not
*/
public function reset_template(string $templatename): bool {
$newtemplates = new stdClass();
// Reset the template to default.
$newtemplates->{$templatename} = '';
if ($templatename == 'listtemplate') {
$newtemplates->listtemplateheader = '';
$newtemplates->listtemplatefooter = '';
}
if ($templatename == 'rsstemplate') {
$newtemplates->rsstitletemplate = '';
}
return $this->update_templates($newtemplates);
}
/** Check if the user can view a specific preset.
*
* @param preset $preset the preset instance.
* @param int $userid the user id to check ($USER->id if null).
* @return bool if the user can view the preset.
*/
public function can_view_preset(preset $preset, ?int $userid = null): bool {
global $USER;
if (!$userid) {
$userid = $USER->id;
}
$presetuserid = $preset->get_userid();
if ($presetuserid && $presetuserid != $userid) {
return has_capability('mod/data:viewalluserpresets', $this->context, $userid);
}
return true;
}
/**
* Returns an array of all the available presets.
*
* @return array A list with the datapreset plugins and the presets saved by users.
*/
public function get_available_presets(): array {
// First load the datapreset plugins that exist within the modules preset dir.
$pluginpresets = static::get_available_plugin_presets();
// Then find the presets that people have saved.
$savedpresets = static::get_available_saved_presets();
return array_merge($pluginpresets, $savedpresets);
}
/**
* Returns an array of all the presets that users have saved to the site.
*
* @return array A list with the preset saved by the users.
*/
public function get_available_saved_presets(): array {
global $USER;
$presets = [];
$fs = get_file_storage();
$files = $fs->get_area_files(DATA_PRESET_CONTEXT, DATA_PRESET_COMPONENT, DATA_PRESET_FILEAREA);
if (empty($files)) {
return $presets;
}
$canviewall = has_capability('mod/data:viewalluserpresets', $this->get_context());
foreach ($files as $file) {
$isnotdirectory = ($file->is_directory() && $file->get_filepath() == '/') || !$file->is_directory();
$userid = $file->get_userid();
$cannotviewfile = !$canviewall && $userid != $USER->id;
if ($isnotdirectory || $cannotviewfile) {
continue;
}
$preset = preset::create_from_storedfile($this, $file);
$presets[] = $preset;
}
return $presets;
}
/**
* Returns an array of all the available plugin presets.
*
* @return array A list with the datapreset plugins.
*/
public static function get_available_plugin_presets(): array {
$presets = [];
$dirs = core_component::get_plugin_list('datapreset');
foreach ($dirs as $dir => $fulldir) {
if (preset::is_directory_a_preset($fulldir)) {
$preset = preset::create_from_plugin(null, $dir);
$presets[] = $preset;
}
}
return $presets;
}
}