MDL-69050 lang: Rename and deprecate filetypes_util methods
[moodle.git] / lib / form / filetypes.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Provides the {@link MoodleQuickForm_filetypes} class.
19  *
20  * @package   core_form
21  * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au>
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 use core_form\filetypes_util;
27 defined('MOODLE_INTERNAL') || die;
29 global $CFG;
30 require_once($CFG->dirroot.'/lib/form/group.php');
32 /**
33  * File types and type groups selection form element.
34  *
35  * @package   core_form
36  * @category  form
37  * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au>
38  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  */
40 class MoodleQuickForm_filetypes extends MoodleQuickForm_group {
42     /** @var array Allow selection from these file types only. */
43     protected $onlytypes = [];
45     /** @var bool Allow selection of 'All file types' (will be stored as '*'). */
46     protected $allowall = true;
48     /** @var bool Skip implicit validation against known file types. */
49     protected $allowunknown = false;
51     /** @var core_form\filetypes_util instance to use as a helper. */
52     protected $util = null;
54     /**
55      * Constructor
56      *
57      * @param string $elementname Element's name
58      * @param string $elementlabel Label(s) for an element
59      * @param array $options element options:
60      *   'onlytypes': Allow selection from these file types only; for example ['onlytypes' => ['web_image']].
61      *   'allowall': Allow to select 'All file types', defaults to true. Does not apply with onlytypes are set.
62      *   'allowunknown': Skip implicit validation against the list of known file types.
63      * @param array|string $attributes Either a typical HTML attribute string or an associative array
64      */
65     public function __construct($elementname = null, $elementlabel = null, $options = null, $attributes = null) {
67         parent::__construct($elementname, $elementlabel);
68         $this->_type = 'filetypes';
70         // Hard-frozen elements do not get the name populated automatically,
71         // which leads to PHP notice. Add it explicitly here.
72         $this->setAttributes(array('name' => $elementname));
73         $this->updateAttributes($attributes);
75         if (is_array($options) && $options) {
76             if (array_key_exists('onlytypes', $options) && is_array($options['onlytypes'])) {
77                 $this->onlytypes = $options['onlytypes'];
78             }
79             if (!$this->onlytypes && array_key_exists('allowall', $options)) {
80                 $this->allowall = (bool)$options['allowall'];
81             }
82             if (array_key_exists('allowunknown', $options)) {
83                 $this->allowunknown = (bool)$options['allowunknown'];
84             }
85         }
87         $this->util = new filetypes_util();
88     }
90     /**
91      * Assemble the elements of the form control.
92      */
93     public function _createElements() {
95         $this->_generateId();
97         $this->setElements([
98             $this->createFormElement('text', 'filetypes', $this->getLabel(), [
99                 'id' => $this->getAttribute('id'),
100             ]),
102             $this->createFormElement('static', 'browser', null,
103                 '<span data-filetypesbrowser="'.$this->getAttribute('id').'"></span>'),
105             $this->createFormElement('static', 'descriptions', null,
106                 '<div data-filetypesdescriptions="'.$this->getAttribute('id').'"></div>')
107         ]);
108     }
110     /**
111      * Return the selected file types.
112      *
113      * @param array $submitted submitted values
114      * @param bool $assoc if true the retured value is associated array
115      * @return array
116      */
117     public function exportValue(&$submitted, $assoc = false) {
119         $value = '';
120         $filetypeselement = null;
122         foreach ($this->_elements as $key => $element) {
123             if ($element->_attributes['name'] === 'filetypes') {
124                 $filetypeselement = $this->_elements[$key];
125             }
126         }
128         if ($filetypeselement) {
129             $formval = $filetypeselement->exportValue($submitted[$this->getName()], false);
130             if ($formval) {
131                 $value = $this->util->normalize_file_types($formval);
132                 if ($value === ['*'] && !$this->allowall) {
133                     $value = [];
134                 }
135                 $value = implode(',', $value);
136             }
137         }
139         return $this->_prepareValue($value, $assoc);
140     }
142     /**
143      * Accepts a renderer (called shortly before the renderer's toHtml() method).
144      *
145      * @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
146      * @param bool $required Whether a group is required
147      * @param string $error An error message associated with a group
148      */
149     public function accept(&$renderer, $required = false, $error = null) {
150         global $PAGE;
152         $PAGE->requires->js_call_amd('core_form/filetypes', 'init', [
153             $this->getAttribute('id'),
154             $this->getLabel(),
155             $this->onlytypes,
156             $this->allowall,
157         ]);
159         if ($this->isFrozen()) {
160             // Don't render the choose button if the control is frozen.
161             foreach ($this->_elements as $key => $element) {
162                 if ($element->_attributes['name'] === 'browser') {
163                     unset($this->_elements[$key]);
164                 }
165             }
166         }
168         parent::accept($renderer, $required, $error);
169     }
171     /**
172      * Called by HTML_QuickForm whenever form event is made on this element
173      *
174      * @param string $event Name of event
175      * @param mixed $arg event arguments
176      * @param object $caller calling object
177      * @return bool
178      */
179     public function onQuickFormEvent($event, $arg, &$caller) {
180         global $OUTPUT;
182         switch ($event) {
183             case 'updateValue':
184                 $value = $this->_findValue($caller->_constantValues);
185                 if (null === $value) {
186                     if ($caller->isSubmitted()) {
187                         $value = $this->_findValue($caller->_submitValues);
188                     } else {
189                         $value = (string)$this->_findValue($caller->_defaultValues);
190                     }
191                 }
192                 if (!is_array($value)) {
193                     $value = array('filetypes' => $value);
194                 }
195                 if ($value['filetypes'] !== null) {
196                     $filetypes = $this->util->normalize_file_types($value['filetypes']);
197                     if ($filetypes === ['*'] && !$this->allowall) {
198                         $filetypes = [];
199                     }
200                     $value['descriptions'] = '<div data-filetypesdescriptions="'.$this->getAttribute('id').'">' .
201                         $OUTPUT->render_from_template('core_form/filetypes-descriptions',
202                             $this->util->describe_file_types($filetypes)).'</div>';
203                 }
204                 $this->setValue($value);
205                 return true;
206                 break;
208         }
210         return parent::onQuickFormEvent($event, $arg, $caller);
211     }
213     /**
214      * Check that the submitted list contains only known and allowed file types.
215      *
216      * The validation obeys the element options 'allowall', 'allowunknown' and
217      * 'onlytypes' passed when creating the element.
218      *
219      * @param array $value Submitted value.
220      * @return string|null Validation error message or null.
221      */
222     public function validateSubmitValue($value) {
224         $value = $value ?? ['filetypes' => null]; // A null $value can arrive here. Coalesce, creating the default array.
226         if (!$this->allowall) {
227             // Assert that there is an actual list provided.
228             $normalized = $this->util->normalize_file_types($value['filetypes']);
229             if (empty($normalized) || $normalized == ['*']) {
230                 return get_string('filetypesnotall', 'core_form');
231             }
232         }
234         if (!$this->allowunknown) {
235             // Assert that all file types are known.
236             $unknown = $this->util->get_unknown_file_types($value['filetypes']);
238             if ($unknown) {
239                 return get_string('filetypesunknown', 'core_form', implode(', ', $unknown));
240             }
241         }
243         if ($this->onlytypes) {
244             // Assert that all file types are allowed here.
245             $notlisted = $this->util->get_not_listed($value['filetypes'], $this->onlytypes);
247             if ($notlisted) {
248                 return get_string('filetypesnotallowed', 'core_form', implode(', ', $notlisted));
249             }
250         }
252         return;
253     }