366 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			366 lines
		
	
	
		
			No EOL
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace local_treestudyplan\form;
 | |
| defined('MOODLE_INTERNAL') || die();
 | |
| 
 | |
| require_once($CFG->dirroot.'/repository/lib.php');
 | |
| use local_treestudyplan\aggregator;
 | |
| use local_treestudyplan\studyplan;
 | |
| use local_treestudyplan\studyplanservice;
 | |
| use local_treestudyplan\courseservice;
 | |
| use local_treestudyplan\form\text_integer;
 | |
| use moodle_exception;
 | |
| use stdClass;
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Moodleform class for the studyplan editor. A Moodleform is used here to facilitate a rich editor 
 | |
|  * in the studyplan description 
 | |
|  */
 | |
| class studyplan_editform extends formbase {
 | |
|     /**
 | |
|      * Capability required to edit study plans
 | |
|      * @var string
 | |
|      */
 | |
|     const CAP_EDIT = "local/treestudyplan:editstudyplan";
 | |
| 
 | |
|     /**
 | |
|      * Translate parameters into customdata. 
 | |
|      * 
 | |
|      * @param object $params The parameters for form initialization
 | |
|      * @return array Form data based on parameters
 | |
|      */    
 | |
|     public static function init_customdata(object $params) {
 | |
|         $customdata = new stdClass;
 | |
|         $customdata->create = $params->mode=='create'?true:false;
 | |
|         if($customdata->create){
 | |
|             $customdata->context = \context::instance_by_id($params->contextid);
 | |
|         } else {
 | |
|             
 | |
|             $customdata->plan = studyplan::find_by_id($params->studyplan_id);
 | |
|             $customdata->context = $customdata->plan->context();
 | |
|             $customdata->simplemodel = $customdata->plan->simple_model();
 | |
|         }
 | |
| 
 | |
|         $customdata->editoroptions = [
 | |
|             'trusttext' => true,
 | |
|             'subdirs' => true,
 | |
|             'maxfiles' => 20,
 | |
|             'maxbytes' => 20*1024*1024,
 | |
|             'context' => \context_system::instance(), // Keep the files in system context
 | |
|         ];
 | |
|         $customdata->fileoptions = [
 | |
|             'subdirs' => 0,
 | |
|             'maxbytes' => 10*1024*1024, // Max 10MiB should be sufficient for a picture.
 | |
|             'areamaxbytes' => 10485760,
 | |
|             'maxfiles' => 1, // Just one file
 | |
|             'accepted_types' => ['.jpg', '.png', '.jpeg', '.svg', '.svgz'],
 | |
|             'return_types' => \FILE_INTERNAL | \FILE_EXTERNAL,
 | |
|         ];
 | |
|         return $customdata; 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Validate security access for this form based on the customdata generated by init_customdata
 | |
|      * Return true if validation passes, false or throw an exception if it does not.
 | |
|      * 
 | |
|      * @param object $customdata The customdata for this form
 | |
|      * @return bool True if security validation passes. 
 | |
|      * @throws \moodle_exception if access denied for a specific reason.
 | |
|      */
 | |
|     public static function check_security(object $customdata) {
 | |
|         /*webservicehelper::require_capabilities(self::CAP_EDIT,$customdata->context); */
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Generate form data from parameters
 | |
|      * Also validate parameters and access permissions here
 | |
|      * 
 | |
|      * @param object $customdata The parameters for form initialization
 | |
|      * @return array Form data based on parameters
 | |
|      */    
 | |
|     public function init_formdata(object $customdata) {
 | |
|         global $DB;
 | |
|         /*  Use direct database retrieval to avoid our abstractions causing trouble
 | |
|             with existing moodle code assumptions. 
 | |
|             The form API does seem needlessly convoluted in it's use, but we need the editor...
 | |
|         */
 | |
|         if($customdata->create) {
 | |
|             $entry = new stdClass;
 | |
|             $entry->context_id = $customdata->context->id;
 | |
|             $entry->aggregation = get_config("local_treestudyplan","aggregation_mode");
 | |
|             $ag_cfg = json_decode(aggregator::create($entry->aggregation, "")->config_string(),true);
 | |
|             
 | |
|             // Determine the next august 1st for default value purposes.
 | |
|             $august = strtotime("first day of august this year");
 | |
|             if($august < time()) {
 | |
|                 $august = strtotime("first day of august next year");
 | |
|             }
 | |
|             $entry->startdate = $august;
 | |
|             $entry->enddate = $august + (364*24*60*60); // Not bothering about leap years here.
 | |
|             $entry->periods = 4;
 | |
|         } else {
 | |
|             $entry = $DB->get_record(studyplan::TABLE, ['id' => $customdata->plan->id()]);
 | |
| 
 | |
|             $entry->startdate = strtotime($customdata->simplemodel['pages'][0]['startdate']);
 | |
|             $entry->enddate = strtotime($customdata->simplemodel['pages'][0]['enddate']);
 | |
|             $entry->periods = $customdata->simplemodel['pages'][0]['periods'];
 | |
|             $ag_cfg = json_decode($customdata->plan->aggregator()->config_string(),true);
 | |
|         }
 | |
| 
 | |
|         // Prepare the editor
 | |
|         $entry = file_prepare_standard_editor(  $entry,
 | |
|             'description',
 | |
|             $customdata->editoroptions,
 | |
|             \context_system::instance(),
 | |
|             'local_treestudyplan',
 | |
|             'studyplan',
 | |
|             ($customdata->create)?null:$customdata->plan->id()
 | |
|         );
 | |
| 
 | |
|         // Prepare file area for the icon
 | |
|         // Get an unused draft itemid which will be used for this form.
 | |
|         $draftitemid = file_get_submitted_draft_itemid('icon');
 | |
|         file_prepare_draft_area(
 | |
|             // The $draftitemid is the target location.
 | |
|             $draftitemid,
 | |
|             // The combination of contextid / component / filearea / itemid
 | |
|             // form the virtual bucket that files are currently stored in
 | |
|             // and will be copied from.
 | |
|             \context_system::instance()->id,
 | |
|             'local_treestudyplan',
 | |
|             'icon',
 | |
|             ($customdata->create)?null:$customdata->plan->id(),
 | |
|             $customdata->fileoptions
 | |
|         );
 | |
|         $entry->icon = $draftitemid;
 | |
| 
 | |
|         // Add aggregation configs to entry.
 | |
| 
 | |
|         foreach ($ag_cfg as $key => $val) {
 | |
|             $entrykey = $entry->aggregation."_".$key;
 | |
|             $entry->$entrykey = $val;
 | |
|         }
 | |
| 
 | |
|         return $entry;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set up the form definition
 | |
|      */
 | |
|     public function definition() {
 | |
|         $mform = $this->_form;
 | |
|         $customdata = (object)$this->_customdata;
 | |
| 
 | |
|         // Register integer type
 | |
|         text_integer::Register();
 | |
| 
 | |
|         // Define the form
 | |
|         $field = 'name';
 | |
|         $mform->addElement('text',$field,
 | |
|             get_string('studyplan_name','local_treestudyplan'),
 | |
|             []);
 | |
|         $mform->addRule($field, null, 'required', null, 'client');
 | |
| 
 | |
|         $field = 'shortname';
 | |
|         $mform->addElement('text',$field,
 | |
|             get_string('studyplan_shortname','local_treestudyplan'),
 | |
|             []);
 | |
|         $mform->addRule($field, null, 'required', null, 'client');
 | |
| 
 | |
|         $field = 'idnumber';
 | |
|         $mform->addElement('text',$field,
 | |
|             get_string('studyplan_idnumber','local_treestudyplan'),
 | |
|             []);
 | |
| 
 | |
|         $contextlist = [];
 | |
|         foreach(courseservice::list_available_categories('edit') as $c){
 | |
|             $contextlist[$c['context_id']] = implode(" / ",$c['category']['path']);
 | |
|         }
 | |
| 
 | |
|         $mform->addElement('autocomplete', 'context_id', 
 | |
|             get_string('studyplan_context','local_treestudyplan'), 
 | |
|             $contextlist);
 | |
| 
 | |
|         $mform->addRule('context_id', null, 'required', null, 'client');
 | |
| 
 | |
|         $mform->addElement(
 | |
|             'filemanager',
 | |
|             'icon',
 | |
|             get_string('studyplan_icon', 'local_treestudyplan'),
 | |
|             null,
 | |
|             $customdata->fileoptions
 | |
|         );
 | |
| 
 | |
|         if ($customdata->create) {
 | |
|             // Only add these fields if a new studyplan is created, to easily initialize the first page
 | |
|             $field = 'startdate';
 | |
|             $mform->addElement('date_selector',$field,
 | |
|                 get_string('studyplan_startdate','local_treestudyplan'),
 | |
|                 []);
 | |
|             $mform->addRule($field, null, 'required', null, 'client');
 | |
| 
 | |
|             $field = 'enddate';
 | |
|             $mform->addElement('date_selector',$field,
 | |
|                 get_string('studyplan_startdate','local_treestudyplan'),
 | |
|                 []);
 | |
|             $mform->addRule($field, null, 'required', null, 'client');
 | |
| 
 | |
|             $field = 'periods';
 | |
|             $mform->addElement('text_integer',$field,
 | |
|                 get_string('studyplan_slots','local_treestudyplan'),
 | |
|                 ["unsigned" => true]);
 | |
|             $mform->setType($field, PARAM_INT);
 | |
|             $mform->addRule($field, null, 'required', null, 'client');
 | |
| 
 | |
|         }
 | |
| 
 | |
|         $aggregators = [];
 | |
|         foreach(aggregator::list_model() as $a){
 | |
|             // Add method only if not deprecated or currently used
 | |
|             if ( $customdata->simplemodel['aggregation'] == $a['id'] || !($a['deprecated']) ) {
 | |
|                 $aggregators[$a['id']] = $a['name'];
 | |
|             }
 | |
|         }
 | |
|         $mform->addElement('select','aggregation',
 | |
|             get_string('choose_aggregation_style','local_treestudyplan'),
 | |
|             $aggregators);
 | |
| 
 | |
|         /* Start Bistate aggregation specific items */
 | |
|         $field = 'bistate_thresh_excellent';
 | |
|         $mform->addElement('text_integer',$field,
 | |
|             get_string('setting_bistate_thresh_excellent','local_treestudyplan'),
 | |
|             ["unsigned" => false],
 | |
|         );
 | |
|         $mform->setType($field, PARAM_INT);
 | |
|         $mform->hideIf($field, "aggregation", "neq", "bistate");
 | |
| 
 | |
|         $field = 'bistate_thresh_good';
 | |
|         $mform->addElement('text_integer',$field,
 | |
|             get_string('setting_bistate_thresh_good','local_treestudyplan'),
 | |
|             ["unsigned" => true],
 | |
|         );
 | |
|         $mform->setType($field, PARAM_INT);
 | |
|         $mform->hideIf($field, "aggregation", "neq", "bistate");
 | |
| 
 | |
|         $field = 'bistate_thresh_completed';
 | |
|         $mform->addElement('text_integer',$field,
 | |
|             get_string('setting_bistate_thresh_completed','local_treestudyplan'),
 | |
|             ["unsigned" => true],
 | |
|         );
 | |
|         $mform->setType($field, PARAM_INT);
 | |
|         $mform->hideIf($field, "aggregation", "neq", "bistate");
 | |
| 
 | |
|         $field = 'bistate_use_failed';
 | |
|         $mform->addElement('checkbox',$field,
 | |
|             get_string('setting_bistate_support_failed','local_treestudyplan'),
 | |
|             [],
 | |
|         );
 | |
|         $mform->hideIf($field, "aggregation", "neq", "bistate");
 | |
|         
 | |
|         $field = 'bistate_accept_pending_as_submitted';
 | |
|         $mform->addElement('checkbox',$field,
 | |
|             get_string('setting_bistate_accept_pending_submitted','local_treestudyplan'),
 | |
|             [],
 | |
|         );
 | |
|         $mform->hideIf($field, "aggregation", "neq", "bistate");        
 | |
| 
 | |
|         /* End Bistate aggregation specific items */
 | |
| 
 | |
|         $mform->addElement('editor', 'description_editor',
 | |
|              get_string('studyplan_description', 'local_treestudyplan'), 
 | |
|              null, 
 | |
|              $customdata->editoroptions);
 | |
|         $mform->setType('description_editor', PARAM_RAW);
 | |
|     }
 | |
| 
 | |
|     /** 
 | |
|      * Process the submitted data and perform necessary actions
 | |
|      * @param object $entry The processed form data;
 | |
|      * @return bool false if submission not successful
 | |
|      * @throws \moodle_exception if an error must be given for a specific reason.
 | |
|      */
 | |
|     protected function process_submitted_data($entry) {
 | |
|         $customdata = (object)$this->_customdata;
 | |
| 
 | |
|         // Add aggregation configs to entry.
 | |
|         $ag_cfg = json_decode(aggregator::create($entry->aggregation, "")->config_string(),true); // Retrieve default config string from selected aggregation method
 | |
|         foreach ($ag_cfg as $key => $val) {
 | |
|             $entrykey = $entry->aggregation."_".$key;
 | |
|             $ag_cfg[$key] = $entry->$entrykey;
 | |
|         }
 | |
|         $aggregation_config = json_encode($ag_cfg);
 | |
| 
 | |
|         if($customdata->create) {
 | |
| 
 | |
|             // Use our own abstraction to update the record, so caches are maintained
 | |
|             $plan = studyplan::add(['name' => $entry->name,
 | |
|                         'shortname' => $entry->shortname,
 | |
|                         'idnumber' => $entry->idnumber,
 | |
|                         'context_id' => $entry->context_id,
 | |
|                         'aggregation' => $entry->aggregation,
 | |
|                         'aggregation_config' => $aggregation_config,
 | |
|                         'startdate' => date("Y-m-d",$entry->startdate),
 | |
|                         'enddate' => date("Y-m-d",$entry->enddate),
 | |
|                         'periods' => $entry->periods,
 | |
|                         ]);
 | |
|             // Process the provided files in the description editor
 | |
|             $entry = file_postupdate_standard_editor($entry,
 | |
|                                                     'description',
 | |
|                                                     $customdata->editoroptions,
 | |
|                                                     \context_system::instance(),
 | |
|                                                     'local_treestudyplan',
 | |
|                                                     'studyplan',
 | |
|                                                     $plan->id());   
 | |
|             // Update the description
 | |
|             $plan->edit([
 | |
|                 'description' => $entry->description,
 | |
|                 'descriptionformat' => $entry->descriptionformat,
 | |
|             ]);
 | |
|         } else {
 | |
|             $plan = $customdata->plan;
 | |
|             
 | |
|             // Process the provided files in the description editor
 | |
|             $entry = file_postupdate_standard_editor($entry,
 | |
|                                                     'description',
 | |
|                                                     $customdata->editoroptions,
 | |
|                                                     \context_system::instance(),
 | |
|                                                     'local_treestudyplan',
 | |
|                                                     'studyplan',
 | |
|                                                     $plan->id());
 | |
| 
 | |
|             // Use our own abstraction to update the record, so caches are maintained
 | |
|             $plan->edit(['name' => $entry->name,
 | |
|                         'shortname' => $entry->shortname,
 | |
|                         'idnumber' => $entry->idnumber,
 | |
|                         'context_id' => $entry->context_id,
 | |
|                         'description' => $entry->description,
 | |
|                         'descriptionformat' => $entry->descriptionformat,
 | |
|                         'aggregation' => $entry->aggregation,
 | |
|                         'aggregation_config' => $aggregation_config,
 | |
|                         ]);
 | |
|         }
 | |
| 
 | |
|         // Now save the icon file in correct part of the File API.
 | |
|         file_save_draft_area_files(
 | |
|             // The $entry->icon property contains the itemid of the draft file area.
 | |
|             $entry->icon,
 | |
|             // The combination of contextid / component / filearea / itemid
 | |
|             // form the virtual bucket that file are stored in.
 | |
|             \context_system::instance()->id,
 | |
|             'local_treestudyplan',
 | |
|             'icon',
 | |
|             $plan->id(),
 | |
|             $customdata->fileoptions
 | |
|         );
 | |
| 
 | |
|         /* Return the simple model of the plan to make sure we can update stuff.
 | |
|            Parse it through the clean_returnvalue function of exernal api (of which studyplanservice is a subclass)
 | |
|            so we return it in a consistent way 
 | |
|         */
 | |
|         return studyplanservice::clean_returnvalue(studyplan::simple_structure(),$plan->simple_model());
 | |
|     }
 | |
| 
 | |
| 
 | |
| } | 
