Skip to content

Commit

Permalink
Merge branch 'MDL-46542' of https://github.com/timhunt/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
stronk7 committed Feb 5, 2020
2 parents 097677f + 8755498 commit a897611
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 80 deletions.
86 changes: 63 additions & 23 deletions lib/form/duration.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,31 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class MoodleQuickForm_duration extends MoodleQuickForm_group {
/**
* Control the fieldnames for form elements
* optional => if true, show a checkbox beside the element to turn it on (or off)
* @var array
*/
protected $_options = array('optional' => false, 'defaultunit' => 60);
/**
* Control the fieldnames for form elements
* optional => if true, show a checkbox beside the element to turn it on (or off)
* @var array
*/
protected $_options = array('optional' => false, 'defaultunit' => MINSECS);

/** @var array associative array of time units (days, hours, minutes, seconds) */
private $_units = null;
/** @var array associative array of time units (days, hours, minutes, seconds) */
private $_units = null;

/**
* constructor
*
* @param string $elementName Element's name
* @param mixed $elementLabel Label(s) for an element
* @param array $options Options to control the element's display. Recognised values are
* 'optional' => true/false - whether to display an 'enabled' checkbox next to the element.
* 'defaultunit' => 1|60|3600|86400|604800 - the default unit to display when the time is blank.
* If not specified, minutes is used.
* 'optional' => true/false - whether to display an 'enabled' checkbox next to the element.
* 'defaultunit' => 1|MINSECS|HOURSECS|DAYSECS|WEEKSECS - the default unit to display when
* the time is blank. If not specified, minutes is used.
* 'units' => array containing some or all of 1, MINSECS, HOURSECS, DAYSECS and WEEKSECS
* which unit choices to offer.
* @param mixed $attributes Either a typical HTML attribute string or an associative array
*/
public function __construct($elementName = null, $elementLabel = null, $options = array(), $attributes = null) {
public function __construct($elementName = null, $elementLabel = null,
$options = array(), $attributes = null) {
// TODO MDL-52313 Replace with the call to parent::__construct().
HTML_QuickForm_element::__construct($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
Expand All @@ -82,14 +85,33 @@ public function __construct($elementName = null, $elementLabel = null, $options
}
$this->_options['defaultunit'] = $options['defaultunit'];
}
if (isset($options['units'])) {
if (!is_array($options['units'])) {
throw new coding_exception(
'When creating a duration form field, units option must be an array.');
}
// Validate and register requested units.
$availableunits = $this->get_units();
$displayunits = [];
foreach ($options['units'] as $requestedunit) {
if (!isset($availableunits[$requestedunit])) {
throw new coding_exception($requestedunit .
' is not a recognised unit in MoodleQuickForm_duration.');
}
$displayunits[$requestedunit] = $availableunits[$requestedunit];
}
krsort($displayunits, SORT_NUMERIC);
$this->_options['units'] = $displayunits;
}
}

/**
* Old syntax of class constructor. Deprecated in PHP7.
*
* @deprecated since Moodle 3.1
*/
public function MoodleQuickForm_duration($elementName = null, $elementLabel = null, $options = array(), $attributes = null) {
public function MoodleQuickForm_duration($elementName = null, $elementLabel = null,
$options = array(), $attributes = null) {
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
self::__construct($elementName, $elementLabel, $options, $attributes);
}
Expand All @@ -102,19 +124,34 @@ public function MoodleQuickForm_duration($elementName = null, $elementLabel = nu
public function get_units() {
if (is_null($this->_units)) {
$this->_units = array(
604800 => get_string('weeks'),
86400 => get_string('days'),
3600 => get_string('hours'),
60 => get_string('minutes'),
WEEKSECS => get_string('weeks'),
DAYSECS => get_string('days'),
HOURSECS => get_string('hours'),
MINSECS => get_string('minutes'),
1 => get_string('seconds'),
);
}
return $this->_units;
}

/**
* Get the units to be used for this field.
*
* The ones specified in the options passed to the constructor, or all by default.
*
* @return array number of seconds => lang string.
*/
protected function get_units_used() {
if (!empty($this->_options['units'])) {
return $this->_options['units'];
} else {
return $this->get_units();
}
}

/**
* Converts seconds to the best possible time unit. for example
* 1800 -> array(30, 60) = 30 minutes.
* 1800 -> [30, MINSECS] = 30 minutes.
*
* @param int $seconds an amout of time in seconds.
* @return array associative array ($number => $unit)
Expand All @@ -123,7 +160,7 @@ public function seconds_to_unit($seconds) {
if ($seconds == 0) {
return array(0, $this->_options['defaultunit']);
}
foreach ($this->get_units() as $unit => $notused) {
foreach ($this->get_units_used() as $unit => $notused) {
if (fmod($seconds, $unit) == 0) {
return array($seconds / $unit, $unit);
}
Expand All @@ -144,14 +181,17 @@ function _createElements() {
}
$this->_elements = array();
// E_STRICT creating elements without forms is nasty because it internally uses $this
$number = $this->createFormElement('text', 'number', get_string('time', 'form'), $attributes, true);
$number = $this->createFormElement('text', 'number',
get_string('time', 'form'), $attributes, true);
$number->set_force_ltr(true);
$this->_elements[] = $number;
unset($attributes['size']);
$this->_elements[] = $this->createFormElement('select', 'timeunit', get_string('timeunit', 'form'), $this->get_units(), $attributes, true);
$this->_elements[] = $this->createFormElement('select', 'timeunit',
get_string('timeunit', 'form'), $this->get_units_used(), $attributes, true);
// If optional we add a checkbox which the user can use to turn if on
if($this->_options['optional']) {
$this->_elements[] = $this->createFormElement('checkbox', 'enabled', null, get_string('enable'), $this->getAttributes(), true);
$this->_elements[] = $this->createFormElement('checkbox', 'enabled', null,
get_string('enable'), $this->getAttributes(), true);
}
foreach ($this->_elements as $element){
if (method_exists($element, 'setHiddenLabel')){
Expand All @@ -165,7 +205,7 @@ function _createElements() {
*
* @param string $event Name of event
* @param mixed $arg event arguments
* @param object $caller calling object
* @param MoodleQuickForm $caller calling object
* @return bool
*/
function onQuickFormEvent($event, $arg, &$caller) {
Expand Down
128 changes: 71 additions & 57 deletions lib/form/tests/duration_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,109 +41,122 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_form_duration_testcase extends basic_testcase {
/** @var MoodleQuickForm Keeps reference of dummy form object */
private $mform;
/** @var MoodleQuickForm_duration Keeps reference of MoodleQuickForm_duration object */
private $element;

/**
* Initalize test wide variable, it is called in start of the testcase
* Get a form that can be used for testing.
*
* @return MoodleQuickForm
*/
protected function setUp() {
parent::setUp();

// Get form data.
protected function get_test_form() {
$form = new temp_form_duration();
$this->mform = $form->getform();
$this->element = $this->mform->addElement('duration', 'duration');
return $form->getform();
}

/**
* Clears the data set in the setUp() method call.
* @see duration_form_element_test::setUp()
* Get a form with a duration element that can be used for testing.
*
* @return array with two elements, a MoodleQuickForm and a MoodleQuickForm_duration.
*/
protected function tearDown() {
$this->element = null;
protected function get_test_form_and_element() {
$mform = $this->get_test_form();
$element = $mform->addElement('duration', 'duration');
return [$mform, $element];
}

/**
* Testcase for testing contructor.
*
* @expectedException coding_exception
* @retrun void
*/
public function test_constructor() {
// Test trying to create with an invalid unit.
$this->element = $this->mform->addElement('duration', 'testel', null, array('defaultunit' => 123, 'optional' => false));
$mform = $this->get_test_form();
$mform->addElement('duration', 'testel', null, ['defaultunit' => 123, 'optional' => false]);
}

/**
* Test contructor only some units.
*/
public function test_constructor_limited_units() {
$mform = $this->get_test_form();
$mform->addElement('duration', 'testel', null, ['units' => [MINSECS, 1], 'optional' => false]);
$html = $mform->toHtml();
$html = preg_replace('~ +>~', '>', $html); // Clean HTML to avoid spurious errors.
$this->assertContains('<option value="60" selected>minutes</option>', $html);
$this->assertContains('<option value="1">seconds</option>', $html);
$this->assertNotContains('value="3600"', $html);
}

/**
* Testcase for testing units (seconds, minutes, hours and days)
*/
public function test_get_units() {
$units = $this->element->get_units();
ksort($units);
$this->assertEquals($units, array(1 => get_string('seconds'), 60 => get_string('minutes'),
3600 => get_string('hours'), 86400 => get_string('days'), 604800 => get_string('weeks')));
[$mform, $element] = $this->get_test_form_and_element();
$units = $element->get_units();
$this->assertEquals($units, [1 => get_string('seconds'), 60 => get_string('minutes'),
3600 => get_string('hours'), 86400 => get_string('days'), 604800 => get_string('weeks')]);
}

/**
* Testcase for testing conversion of seconds to the best possible unit
*/
public function test_seconds_to_unit() {
$this->assertEquals(array(0, 60), $this->element->seconds_to_unit(0)); // Zero minutes, for a nice default unit.
$this->assertEquals(array(1, 1), $this->element->seconds_to_unit(1));
$this->assertEquals(array(3601, 1), $this->element->seconds_to_unit(3601));
$this->assertEquals(array(1, 60), $this->element->seconds_to_unit(60));
$this->assertEquals(array(3, 60), $this->element->seconds_to_unit(180));
$this->assertEquals(array(1, 3600), $this->element->seconds_to_unit(3600));
$this->assertEquals(array(2, 3600), $this->element->seconds_to_unit(7200));
$this->assertEquals(array(1, 86400), $this->element->seconds_to_unit(86400));
$this->assertEquals(array(25, 3600), $this->element->seconds_to_unit(90000));

$this->element = $this->mform->addElement('duration', 'testel', null, array('defaultunit' => 86400, 'optional' => false));
$this->assertEquals(array(0, 86400), $this->element->seconds_to_unit(0)); // Zero minutes, for a nice default unit.
[$mform, $element] = $this->get_test_form_and_element();
$this->assertEquals([0, MINSECS], $element->seconds_to_unit(0)); // Zero minutes, for a nice default unit.
$this->assertEquals([1, 1], $element->seconds_to_unit(1));
$this->assertEquals([3601, 1], $element->seconds_to_unit(3601));
$this->assertEquals([1, MINSECS], $element->seconds_to_unit(60));
$this->assertEquals([3, MINSECS], $element->seconds_to_unit(180));
$this->assertEquals([1, HOURSECS], $element->seconds_to_unit(3600));
$this->assertEquals([2, HOURSECS], $element->seconds_to_unit(7200));
$this->assertEquals([1, DAYSECS], $element->seconds_to_unit(86400));
$this->assertEquals([25, HOURSECS], $element->seconds_to_unit(90000));

$element = $mform->addElement('duration', 'testel', null,
['defaultunit' => DAYSECS, 'optional' => false]);
$this->assertEquals([0, DAYSECS], $element->seconds_to_unit(0)); // Zero minutes, for a nice default unit.
}

/**
* Testcase to check generated timestamp
*/
public function test_exportValue() {
/** @var MoodleQuickForm_duration $el */
$el = $this->mform->addElement('duration', 'testel');
$values = array('testel' => array('number' => 10, 'timeunit' => 1));
$this->assertEquals(array('testel' => 10), $el->exportValue($values, true));
$mform = $this->get_test_form();
$el = $mform->addElement('duration', 'testel');
$values = ['testel' => ['number' => 10, 'timeunit' => 1]];
$this->assertEquals(['testel' => 10], $el->exportValue($values, true));
$this->assertEquals(10, $el->exportValue($values));
$values = array('testel' => array('number' => 3, 'timeunit' => 60));
$this->assertEquals(array('testel' => 180), $el->exportValue($values, true));
$values = ['testel' => ['number' => 3, 'timeunit' => MINSECS]];
$this->assertEquals(['testel' => 180], $el->exportValue($values, true));
$this->assertEquals(180, $el->exportValue($values));
$values = array('testel' => array('number' => 1.5, 'timeunit' => 60));
$this->assertEquals(array('testel' => 90), $el->exportValue($values, true));
$values = ['testel' => ['number' => 1.5, 'timeunit' => MINSECS]];
$this->assertEquals(['testel' => 90], $el->exportValue($values, true));
$this->assertEquals(90, $el->exportValue($values));
$values = array('testel' => array('number' => 2, 'timeunit' => 3600));
$this->assertEquals(array('testel' => 7200), $el->exportValue($values, true));
$values = ['testel' => ['number' => 2, 'timeunit' => HOURSECS]];
$this->assertEquals(['testel' => 7200], $el->exportValue($values, true));
$this->assertEquals(7200, $el->exportValue($values));
$values = array('testel' => array('number' => 1, 'timeunit' => 86400));
$this->assertEquals(array('testel' => 86400), $el->exportValue($values, true));
$values = ['testel' => ['number' => 1, 'timeunit' => DAYSECS]];
$this->assertEquals(['testel' => 86400], $el->exportValue($values, true));
$this->assertEquals(86400, $el->exportValue($values));
$values = array('testel' => array('number' => 0, 'timeunit' => 3600));
$this->assertEquals(array('testel' => 0), $el->exportValue($values, true));
$values = ['testel' => ['number' => 0, 'timeunit' => HOURSECS]];
$this->assertEquals(['testel' => 0], $el->exportValue($values, true));
$this->assertEquals(0, $el->exportValue($values));

$el = $this->mform->addElement('duration', 'testel', null, array('optional' => true));
$values = array('testel' => array('number' => 10, 'timeunit' => 1));
$this->assertEquals(array('testel' => 0), $el->exportValue($values, true));
$el = $mform->addElement('duration', 'testel', null, ['optional' => true]);
$values = ['testel' => ['number' => 10, 'timeunit' => 1]];
$this->assertEquals(['testel' => 0], $el->exportValue($values, true));
$this->assertEquals(0, $el->exportValue($values));
$values = array('testel' => array('number' => 20, 'timeunit' => 1, 'enabled' => 1));
$this->assertEquals(array('testel' => 20), $el->exportValue($values, true));
$values = ['testel' => ['number' => 20, 'timeunit' => 1, 'enabled' => 1]];
$this->assertEquals(['testel' => 20], $el->exportValue($values, true));
$this->assertEquals(20, $el->exportValue($values));

// Optional element.
$el2 = $this->mform->addElement('duration', 'testel', '', ['optional' => true]);
$values = array('testel' => array('number' => 10, 'timeunit' => 1, 'enabled' => 1));
$this->assertEquals(array('testel' => 10), $el2->exportValue($values, true));
$el2 = $mform->addElement('duration', 'testel', '', ['optional' => true]);
$values = ['testel' => ['number' => 10, 'timeunit' => 1, 'enabled' => 1]];
$this->assertEquals(['testel' => 10], $el2->exportValue($values, true));
$this->assertEquals(10, $el2->exportValue($values));
$values = array('testel' => array('number' => 10, 'timeunit' => 1, 'enabled' => 0));
$this->assertEquals(array('testel' => 0), $el2->exportValue($values, true));
$values = ['testel' => ['number' => 10, 'timeunit' => 1, 'enabled' => 0]];
$this->assertEquals(['testel' => 0], $el2->exportValue($values, true));
$this->assertEquals(null, $el2->exportValue($values));
}
}
Expand All @@ -158,6 +171,7 @@ class temp_form_duration extends moodleform {
public function definition() {
// No definition required.
}

/**
* Returns form reference
* @return MoodleQuickForm
Expand Down

0 comments on commit a897611

Please sign in to comment.