Merge branch 'MDL-73990-master' of https://github.com/sharidas/moodle
[moodle.git] / lib / form / filetypes.php
blob29838ded3e6330d26309c85ae937498436bd79ed
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.
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.
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
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.
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
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
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
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'];
79 if (!$this->onlytypes && array_key_exists('allowall', $options)) {
80 $this->allowall = (bool)$options['allowall'];
82 if (array_key_exists('allowunknown', $options)) {
83 $this->allowunknown = (bool)$options['allowunknown'];
87 $this->util = new filetypes_util();
90 /**
91 * Assemble the elements of the form control.
93 public function _createElements() {
95 $this->_generateId();
97 $this->setElements([
98 $this->createFormElement('text', 'filetypes', $this->getLabel(), [
99 'id' => $this->getAttribute('id'),
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>')
111 * Return the selected file types.
113 * @param array $submitted submitted values
114 * @param bool $assoc if true the retured value is associated array
115 * @return array
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];
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 = [];
135 $value = implode(',', $value);
139 return $this->_prepareValue($value, $assoc);
143 * Accepts a renderer (called shortly before the renderer's toHtml() method).
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
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,
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]);
168 parent::accept($renderer, $required, $error);
172 * Called by HTML_QuickForm whenever form event is made on this element
174 * @param string $event Name of event
175 * @param mixed $arg event arguments
176 * @param object $caller calling object
177 * @return bool
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);
192 if (!is_array($value)) {
193 $value = array('filetypes' => $value);
195 if ($value['filetypes'] !== null) {
196 $filetypes = $this->util->normalize_file_types($value['filetypes']);
197 if ($filetypes === ['*'] && !$this->allowall) {
198 $filetypes = [];
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>';
204 $this->setValue($value);
205 return true;
206 break;
210 return parent::onQuickFormEvent($event, $arg, $caller);
214 * Check that the submitted list contains only known and allowed file types.
216 * The validation obeys the element options 'allowall', 'allowunknown' and
217 * 'onlytypes' passed when creating the element.
219 * @param array $value Submitted value.
220 * @return string|null Validation error message or null.
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');
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));
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));
252 return;