Replace generic alert, form and table templates with new Bootstrap equivalents
This commit is contained in:
341
models/Form.php
341
models/Form.php
@@ -3,7 +3,8 @@
|
||||
* Form.php
|
||||
* Contains key class Form.
|
||||
*
|
||||
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
|
||||
* Global Data Lab code (C) Radboud University Nijmegen
|
||||
* Programming (C) Aaron van Geffen, 2015-2022
|
||||
*****************************************************************************/
|
||||
|
||||
class Form
|
||||
@@ -12,9 +13,11 @@ class Form
|
||||
public $request_url;
|
||||
public $content_above;
|
||||
public $content_below;
|
||||
private $fields;
|
||||
private $data;
|
||||
private $missing;
|
||||
private $fields = [];
|
||||
private $data = [];
|
||||
private $missing = [];
|
||||
private $submit_caption;
|
||||
private $trim_inputs;
|
||||
|
||||
// NOTE: this class does not verify the completeness of form options.
|
||||
public function __construct($options)
|
||||
@@ -24,9 +27,42 @@ class Form
|
||||
$this->fields = !empty($options['fields']) ? $options['fields'] : [];
|
||||
$this->content_below = !empty($options['content_below']) ? $options['content_below'] : null;
|
||||
$this->content_above = !empty($options['content_above']) ? $options['content_above'] : null;
|
||||
$this->submit_caption = !empty($options['submit_caption']) ? $options['submit_caption'] : 'Save information';
|
||||
$this->trim_inputs = !empty($options['trim_inputs']);
|
||||
}
|
||||
|
||||
public function verify($post)
|
||||
public function getFields()
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getSubmitButtonCaption()
|
||||
{
|
||||
return $this->submit_caption;
|
||||
}
|
||||
|
||||
public function getMissing()
|
||||
{
|
||||
return $this->missing;
|
||||
}
|
||||
|
||||
public function setData($data)
|
||||
{
|
||||
$this->verify($data, true);
|
||||
$this->missing = [];
|
||||
}
|
||||
|
||||
public function setFieldAsMissing($field)
|
||||
{
|
||||
$this->missing[] = $field;
|
||||
}
|
||||
|
||||
public function verify($post, $initalisation = false)
|
||||
{
|
||||
$this->data = [];
|
||||
$this->missing = [];
|
||||
@@ -41,30 +77,43 @@ class Form
|
||||
}
|
||||
|
||||
// No data present at all for this field?
|
||||
if ((!isset($post[$field_id]) || $post[$field_id] == '') && empty($field['is_optional']))
|
||||
if ((!isset($post[$field_id]) || $post[$field_id] == '') &&
|
||||
$field['type'] !== 'captcha')
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
if (empty($field['is_optional']))
|
||||
$this->missing[] = $field_id;
|
||||
|
||||
if ($field['type'] === 'select' && !empty($field['multiple']))
|
||||
$this->data[$field_id] = [];
|
||||
else
|
||||
$this->data[$field_id] = '';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify data for all fields
|
||||
// Should we trim this?
|
||||
if ($this->trim_inputs && $field['type'] !== 'captcha' && empty($field['multiple']))
|
||||
$post[$field_id] = trim($post[$field_id]);
|
||||
|
||||
// Using a custom validation function?
|
||||
if (isset($field['validate']) && is_callable($field['validate']))
|
||||
{
|
||||
// Validation functions can clean up the data if passed by reference
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
|
||||
// Evaluate validation functions as boolean to see if data is missing
|
||||
if (!$field['validate']($post[$field_id]))
|
||||
$this->missing[] = $field_id;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify data by field type
|
||||
switch ($field['type'])
|
||||
{
|
||||
case 'select':
|
||||
case 'radio':
|
||||
// Skip validation? Dangerous territory!
|
||||
if (isset($field['verify_options']) && $field['verify_options'] === false)
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
// Check whether selected option is valid.
|
||||
elseif (isset($post[$field_id]) && !isset($field['options'][$post[$field_id]]))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
continue 2;
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
$this->validateSelect($field_id, $field, $post);
|
||||
break;
|
||||
|
||||
case 'checkbox':
|
||||
@@ -73,61 +122,22 @@ class Form
|
||||
break;
|
||||
|
||||
case 'color':
|
||||
// Colors are stored as a string of length 3 or 6 (hex)
|
||||
if (!isset($post[$field_id]) || (strlen($post[$field_id]) != 3 && strlen($post[$field_id]) != 6))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
continue 2;
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
$this->validateColor($field_id, $field, $post);
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
// Needs to be verified elsewhere!
|
||||
// Asset needs to be processed out of POST! This is just a filename.
|
||||
$this->data[$field_id] = isset($post[$field_id]) ? $post[$field_id] : '';
|
||||
break;
|
||||
|
||||
case 'numeric':
|
||||
$data = isset($post[$field_id]) ? $post[$field_id] : '';
|
||||
// Do we need to check bounds?
|
||||
if (isset($field['min_value']) && is_numeric($data))
|
||||
{
|
||||
if (is_float($field['min_value']) && (float) $data < $field['min_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0.0;
|
||||
}
|
||||
elseif (is_int($field['min_value']) && (int) $data < $field['min_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $data;
|
||||
}
|
||||
elseif (isset($field['max_value']) && is_numeric($data))
|
||||
{
|
||||
if (is_float($field['max_value']) && (float) $data > $field['max_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0.0;
|
||||
}
|
||||
elseif (is_int($field['max_value']) && (int) $data > $field['max_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $data;
|
||||
}
|
||||
// Does it look numeric?
|
||||
elseif (is_numeric($data))
|
||||
{
|
||||
$this->data[$field_id] = $data;
|
||||
}
|
||||
// Let's consider it missing, then.
|
||||
else
|
||||
$this->validateNumeric($field_id, $field, $post);
|
||||
break;
|
||||
|
||||
case 'captcha':
|
||||
if (isset($_POST['g-recaptcha-response']) && !$initalisation)
|
||||
$this->validateCaptcha($field_id);
|
||||
elseif (!$initalisation)
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
@@ -137,29 +147,200 @@ class Form
|
||||
case 'text':
|
||||
case 'textarea':
|
||||
default:
|
||||
$this->data[$field_id] = isset($post[$field_id]) ? $post[$field_id] : '';
|
||||
$this->validateText($field_id, $field, $post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setData($data)
|
||||
private function validateCaptcha($field_id)
|
||||
{
|
||||
$this->verify($data);
|
||||
$this->missing = [];
|
||||
$postdata = http_build_query([
|
||||
'secret' => RECAPTCHA_API_SECRET,
|
||||
'response' => $_POST['g-recaptcha-response'],
|
||||
]);
|
||||
|
||||
$opts = [
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-type: application/x-www-form-urlencoded',
|
||||
'content' => $postdata,
|
||||
]
|
||||
];
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
$result = file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context);
|
||||
$check = json_decode($result);
|
||||
|
||||
if ($check->success)
|
||||
{
|
||||
$this->data[$field_id] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->data[$field_id] = 0;
|
||||
$this->missing[] = $field_id;
|
||||
}
|
||||
}
|
||||
|
||||
public function getFields()
|
||||
private function validateColor($field_id, array $field, array $post)
|
||||
{
|
||||
return $this->fields;
|
||||
// Colors are stored as a string of length 3 or 6 (hex)
|
||||
if (!isset($post[$field_id]) || (strlen($post[$field_id]) != 3 && strlen($post[$field_id]) != 6))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
}
|
||||
|
||||
public function getData()
|
||||
private function validateNumeric($field_id, array $field, array $post)
|
||||
{
|
||||
return $this->data;
|
||||
$data = isset($post[$field_id]) ? $post[$field_id] : '';
|
||||
|
||||
// Sanity check: does this even look numeric?
|
||||
if (!is_numeric($data))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do we need to a minimum bound?
|
||||
if (isset($field['min_value']))
|
||||
{
|
||||
if (is_float($field['min_value']) && (float) $data < $field['min_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0.0;
|
||||
}
|
||||
elseif (is_int($field['min_value']) && (int) $data < $field['min_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// What about a maximum bound?
|
||||
if (isset($field['max_value']))
|
||||
{
|
||||
if (is_float($field['max_value']) && (float) $data > $field['max_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0.0;
|
||||
}
|
||||
elseif (is_int($field['max_value']) && (int) $data > $field['max_value'])
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$this->data[$field_id] = $data;
|
||||
}
|
||||
|
||||
public function getMissing()
|
||||
private function validateSelect($field_id, array $field, array $post)
|
||||
{
|
||||
return $this->missing;
|
||||
// Skip validation? Dangerous territory!
|
||||
if (isset($field['verify_options']) && $field['verify_options'] === false)
|
||||
{
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether selected option is valid.
|
||||
if (($field['type'] !== 'select' || empty($field['multiple'])) && empty($field['has_groups']))
|
||||
{
|
||||
if (isset($post[$field_id]) && !isset($field['options'][$post[$field_id]]))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
return;
|
||||
}
|
||||
else
|
||||
$this->data[$field_id] = $post[$field_id];
|
||||
}
|
||||
// Multiple selections involve a bit more work.
|
||||
elseif (!empty($field['multiple']) && empty($field['has_groups']))
|
||||
{
|
||||
$this->data[$field_id] = [];
|
||||
if (!is_array($post[$field_id]))
|
||||
{
|
||||
if (isset($field['options'][$post[$field_id]]))
|
||||
$this->data[$field_id][] = $post[$field_id];
|
||||
else
|
||||
$this->missing[] = $field_id;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($post[$field_id] as $option)
|
||||
{
|
||||
if (isset($field['options'][$option]))
|
||||
$this->data[$field_id][] = $option;
|
||||
}
|
||||
|
||||
if (empty($this->data[$field_id]))
|
||||
$this->missing[] = $field_id;
|
||||
}
|
||||
// Any optgroups involved?
|
||||
elseif (!empty($field['has_groups']))
|
||||
{
|
||||
if (!isset($post[$field_id]))
|
||||
{
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Expensive: iterate over all groups until the value selected has been found.
|
||||
foreach ($field['options'] as $label => $options)
|
||||
{
|
||||
if (is_array($options))
|
||||
{
|
||||
// Consider each of the options as a valid a value.
|
||||
foreach ($options as $value => $label)
|
||||
{
|
||||
if ($post[$field_id] === $value)
|
||||
{
|
||||
$this->data[$field_id] = $options;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is an ungrouped value in disguise! Treat it as such.
|
||||
if ($post[$field_id] === $options)
|
||||
{
|
||||
$this->data[$field_id] = $options;
|
||||
return;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've reached this point, we'll consider the data invalid.
|
||||
$this->missing[] = $field_id;
|
||||
$this->data[$field_id] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnexpectedValueException('Unexpected field configuration in validateSelect!');
|
||||
}
|
||||
}
|
||||
|
||||
private function validateText($field_id, array $field, array $post)
|
||||
{
|
||||
$this->data[$field_id] = isset($post[$field_id]) ? $post[$field_id] : '';
|
||||
|
||||
// Trim leading and trailing whitespace?
|
||||
if (!empty($field['trim']))
|
||||
$this->data[$field_id] = trim($this->data[$field_id]);
|
||||
|
||||
// Is there a length limit to enforce?
|
||||
if (isset($field['maxlength']) && strlen($post[$field_id]) > $field['maxlength']) {
|
||||
$post[$field_id] = substr($post[$field_id], 0, $field['maxlength']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* GenericTable.php
|
||||
* Contains key class GenericTable.
|
||||
*
|
||||
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
|
||||
* Global Data Lab code (C) Radboud University Nijmegen
|
||||
* Programming (C) Aaron van Geffen, 2015-2021
|
||||
*****************************************************************************/
|
||||
|
||||
class GenericTable
|
||||
@@ -19,7 +20,7 @@ class GenericTable
|
||||
|
||||
public $form_above;
|
||||
public $form_below;
|
||||
|
||||
private $table_class;
|
||||
private $sort_direction;
|
||||
private $sort_order;
|
||||
private $base_url;
|
||||
@@ -84,6 +85,8 @@ class GenericTable
|
||||
else
|
||||
$this->body = $options['no_items_label'] ?? '';
|
||||
|
||||
$this->table_class = $options['table_class'] ?? '';
|
||||
|
||||
// Got a title?
|
||||
$this->title = $options['title'] ?? '';
|
||||
$this->title_class = $options['title_class'] ?? '';
|
||||
@@ -105,6 +108,7 @@ class GenericTable
|
||||
|
||||
$header = [
|
||||
'class' => isset($column['class']) ? $column['class'] : '',
|
||||
'cell_class' => isset($column['cell_class']) ? $column['cell_class'] : null,
|
||||
'colspan' => !empty($column['header_colspan']) ? $column['header_colspan'] : 1,
|
||||
'href' => $isSortable ? $this->getLink($this->start, $key, $sortDirection) : null,
|
||||
'label' => $column['header'],
|
||||
@@ -168,6 +172,11 @@ class GenericTable
|
||||
return $this->pageIndex;
|
||||
}
|
||||
|
||||
public function getTableClass()
|
||||
{
|
||||
return $this->table_class;
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
@@ -196,6 +205,7 @@ class GenericTable
|
||||
|
||||
// Append the cell to the row.
|
||||
$newRow['cells'][] = [
|
||||
'class' => $column['cell_class'] ?? '',
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user