diff --git a/composer.json b/composer.json index 3af5364..eacdda9 100644 --- a/composer.json +++ b/composer.json @@ -8,5 +8,8 @@ "require-dev": { "simplemachines/smf2.1": "dev-unittest", "phpunit/phpunit": "^8.5" + }, + "require": { + "php": ">=7.4" } } diff --git a/src/Class-CustomForm.php b/src/Class-CustomForm.php index 090f14d..625665b 100644 --- a/src/Class-CustomForm.php +++ b/src/Class-CustomForm.php @@ -1,5 +1,15 @@ + * @copyright Copyright (c) 2014, John Rayes + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + interface CustomForm { /* @@ -7,11 +17,10 @@ interface CustomForm * * @param array $field The field as returned by {@link total_getCustomForm()}. * @param string $value Field value. - * @param bool $exists Whether the value exists/is not empty. * * @access public */ - public function __construct($field, $value, $exists); + public function __construct(array $field, string $value); /* * Sets the input so the user can enter a value. @@ -20,58 +29,55 @@ public function __construct($field, $value, $exists); * @access public */ public function setHtml(); - public function validate(); + + /* + * Gets the value. This method should handle if a specific field type must be sanitized. + * + * @access public + * @return string + */ + public function getValue(): string; + public function validate(): bool; } abstract class CustomFormBase implements CustomForm { - public $input_html; - public $output_html; - protected $field; - protected $err = false; - protected $exists = false; - protected $type_vars = array(); - protected $value = ''; - protected $size = 0; - protected $default = ''; - protected $required = false; - - public function __construct($field, $value, $exists) + public string $input_html; + public string $output_html; + protected array $field; + protected array $err = []; + protected bool $exists = false; + protected array $type_vars = array(); + protected string $value = ''; + protected int $size = 0; + protected string $default = ''; + protected bool $required = false; + + public function __construct(array $field, string $value) { $this->field = $field; $this->value = $value; - $this->exists = $exists; + $this->exists = !empty($value); } /* * Gets the error generated by the validation method. * * @access public - * @return string|false The error string or false for no error. + * @return array */ - public function getError() + public function getError(): array { return $this->err; } - /* - * Gets the value. This method may be overridden if a specific field type must be sanitized. - * - * @access public - * @return string - */ - public function getValue() - { - return $this->value; - } - /** * Returns the input so the user can enter a value. * * @access public - * @return mixed + * @return string */ - public function getInputHtml() + public function getInputHtml(): string { return $this->input_html; } @@ -80,9 +86,9 @@ public function getInputHtml() * Returns the output. It's the field's value formatted acccording to its criteria. * * @access public - * @return mixed + * @return string */ - public function getOutputHtml() + public function getOutputHtml(): string { return $this->output_html; } @@ -118,16 +124,23 @@ public function setHtml() { global $txt; $true = (!$this->exists && $this->default) || $this->value; - $this->input_html = ''; - $this->output_html = $true ? $txt['yes'] : $txt['no']; + $this->input_html .= sprintf( + '', + 'CustomFormField', + $this->field['id_field'], + $true ? ' checked' : '' + ); + $this->output_html = $txt[$this->getValue()]; } - public function validate() + public function validate(): bool { - // Nothing needed here, really. It's just a get out of jail free card. "This card may be kept until needed, or sold." + // Nothing needed here, really. It's just a get out of jail + // free card. "This card may be kept until needed, or sold." + return true; } - public function getValue() + public function getValue(): string { - return (!$this->exists && $this->default) || $this->value; + return (!$this->exists && $this->default) || $this->value ? 'yes' : 'no'; } } @@ -135,35 +148,40 @@ class CustomForm_select extends CustomFormBase { public function setHtml() { - $this->input_html = '', + 'CustomFormField', + $this->field['id_field'] + ); foreach ($this->type_vars as $v) { - $true = (!$this->exists && $this->default == $v) || $this->value == $v; - $this->input_html .= '' . $v . ''; + $this->input_html .= sprintf( + ' %s', + (!$this->exists && $this->default == $v) || $this->value == $v + ? ' checked="checked"' + : '', + $v + ); if ($true) $this->output_html = $v; } $this->input_html .= ''; } - public function validate() + public function validate(): bool { - $found = false; - $opts = array_flip($this->type_vars); - if (isset($this->value, $opts[$this->value])) - $found = true; + $found = isset(array_flip($this->type_vars)[$this->value]); if (!$found && $this->required) $this->err = array('pf_invalid_value', $this->field['name']); + + return $found; } - public function getValue() + public function getValue(): string { - $value = $this->default; - $opts = array_flip($this->type_vars); - if (isset($this->value, $opts[$this->value])) - $value = $this->value; - - return $value; + return isset(array_flip($this->type_vars)[$this->value]) + ? $this->value + : $this->default; } } @@ -174,8 +192,15 @@ public function setHtml() $this->input_html = '
'; foreach ($this->type_vars as $v) { - $true = (!$this->exists && $this->default == $v) || $this->value == $v; - $this->input_html .= '
'; + $this->input_html .= sprintf( + '
', + 'CustomFormField', + $this->field['id_field'], + (!$this->exists && $this->default == $v) || $this->value == $v + ? ' checked="checked"' + : '', + $v + ); if ($true) $this->output_html = $v; } @@ -188,9 +213,14 @@ class CustomForm_text extends CustomFormBase public function setHtml() { $this->output_html = $this->value; - $this->input_html = ''; + $this->input_html = sprintf( + '', + 'CustomFormField', + $this->field['id_field'], + $this->value + ); } - public function getValue() + public function getValue(): string { global $smcFunc; if (!empty($this->size)) @@ -201,7 +231,7 @@ public function getValue() return $this->value; } - public function validate() + public function validate(): bool { if ($this->exists && $this->required) $this->err = array('pf_invalid_value', $this->field['name']); @@ -211,7 +241,7 @@ public function validate() //~ fatal_error('Mask "' . $this->field['mask'] . '" not found for field "' . $this->field['name'] . '" at ID #' . $this->field['id_field'] . '.', false); //~ $mask = new $class_name($this->value, $this->field); - //~ $mask->validate(); + //~ $mask->validate(): bool; //~ if (false !== ($err = $mask->getError())) //~ $this->err = $err; } @@ -223,14 +253,14 @@ public function setHtml() { $this->output_html = $this->value; @list ($rows, $cols) = @explode(',', $this->default); - $this->input_html = ''; + $this->input_html = ''; } } interface CustomFormFieldMask { public function __construct($value, $field); - public function validate(); + public function validate(): bool; } abstract class CustomFormFieldMaskBase implements CustomFormFieldMask @@ -253,7 +283,7 @@ public function getError() class CustomFormFieldMask_email extends CustomFormFieldMaskBase { - public function validate() + public function validate(): bool { if (!preg_match('~^[0-9A-Za-z=_+\-/][0-9A-Za-z=_\'+\-/\.]*@[\w\-]+(\.[\w\-]+)*(\.[\w]{2,6})$~', $this->value)) $this->err = array('pf_invalid_value', $this->field['name']); @@ -262,7 +292,7 @@ public function validate() class CustomFormFieldMask_regex extends CustomFormFieldMaskBase { - public function validate() + public function validate(): bool { if (!preg_match($this->field['regex'], $this->value)) if (!empty($this->field['err'])) @@ -274,7 +304,7 @@ public function validate() class CustomFormFieldMask_number extends CustomFormFieldMaskBase { - public function validate() + public function validate(): bool { if (!preg_match('/^\s*([0-9]+)\s*$/', $this->value)) $this->err = array('pf_invalid_value', $this->field['name']); @@ -283,7 +313,7 @@ public function validate() class CustomFormFieldMask_float extends CustomFormFieldMaskBase { - public function validate() + public function validate(): bool { if (!preg_match('/^\s*([0-9]+(\.[0-9]+)?)\s*$/', $this->value)) $this->err = array('pf_invalid_value', $this->field['name']); @@ -292,7 +322,7 @@ public function validate() class CustomFormFieldMask_nohtml extends CustomFormFieldMaskBase { - public function validate() + public function validate(): bool { if (strip_tags($this->value) != $this->value) $this->err = array('pf_invalid_value', $this->field['name']); diff --git a/src/CustomForm.php b/src/CustomForm.php index ac86632..50c5eb7 100644 --- a/src/CustomForm.php +++ b/src/CustomForm.php @@ -114,10 +114,9 @@ function CustomForm() $type = new $class_name($field, $value, !empty($value)); $type->setOptions(); - $type->validate(); - if (false !== ($err = $type->getError())) + if (!$type->validate()) { - $post_errors[] = $err; + $post_errors[] = $type->getError(); // Do the 'fail form/field' stuff. $data[$i]['failed'] = true; $fail_submit = true; diff --git a/src/Subs-CustomForm.php b/src/Subs-CustomForm.php index b2fdd6c..6b4a6e5 100644 --- a/src/Subs-CustomForm.php +++ b/src/Subs-CustomForm.php @@ -8,12 +8,14 @@ * @license http://opensource.org/licenses/MIT MIT */ -function customform_actions(&$action_array) +declare(strict_types=1); + +function customform_actions(array &$action_array) { $action_array['form'] = array('CustomForm.php', 'CustomForm'); } -function customform_admin_areas(&$admin_areas) +function customform_admin_areas(array &$admin_areas) { global $txt; @@ -21,7 +23,7 @@ function customform_admin_areas(&$admin_areas) $admin_areas['config']['areas']['modsettings']['subsections']['customform'] = array($txt['customform_tabheader']); } -function customform_modify_modifications(&$sub_actions) +function customform_modify_modifications(array &$sub_actions) { $sub_actions['customform'] = 'ModifyCustomFormSettings'; } diff --git a/tests/Test.php b/tests/Test.php index 6f654eb..aeae80d 100644 --- a/tests/Test.php +++ b/tests/Test.php @@ -16,4 +16,70 @@ public function testFindClasses(): void $this->assertContains('text', $classes); $this->assertContains('textarea', $classes); } + + /** + * @dataProvider checkboxProvider + */ + public function testCheckbox(string $type_vars, string $value, string $expected): void + { + $type = new CustomForm_check( + [ + 'id_field' => '', + 'title' => '', + 'text' => '', + 'type' => '', + 'type_vars' => $type_vars + ], + $value + ); + $type->setOptions(); + $this->assertTrue($type->validate()); + $this->assertEmpty($type->getError()); + $this->assertEquals($expected, $type->getValue()); + } + + /** + * @return string[][] + */ + public function checkboxProvider(): array + { + return [ + ['default=on', '', 'yes'], + ['default=on', 'boop', 'yes'], + ['default=', '', 'no'] + ]; + } + + /** + * @dataProvider selectProvider + */ + public function testselect(string $type_vars, string $value, string $expected): void + { + $type = new CustomForm_select( + [ + 'id_field' => '', + 'title' => '', + 'text' => '', + 'type' => '', + 'type_vars' => $type_vars + ], + $value + ); + $type->setOptions(); + $this->assertTrue($type->validate()); + $this->assertEmpty($type->getError()); + $this->assertEquals($expected, $type->getValue()); + } + + /** + * @return string[][] + */ + public function selectProvider(): array + { + return [ + ['gold,silver,bronze,default=silver', '', 'silver'], + ['gold,silver,bronze,default=', 'silver', 'silver'] + ]; + } + }