<?php
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
class FormBuilder {
private $items = [];
private $hiddenitems = [];
private $title = "";
private $icon = "";
private $buttons = [];
private $action = "action.php";
private $method = "POST";
private $id = "editform";
/**
* Create a form with autogenerated HTML.
*
* @param string $title Form title/heading
* @param string $icon FontAwesone icon next to the title.
* @param string $action URL to submit the form to.
* @param string $method Form submission method (POST, GET, etc.)
*/
public function __construct(string $title = "Untitled Form", string $icon = "fas fa-file-alt", string $action = "action.php", string $method = "POST") {
$this->title = $title;
$this->icon = $icon;
$this->action = $action;
$this->method = $method;
}
/**
* Set the title of the form.
* @param string $title
*/
public function setTitle(string $title) {
$this->title = $title;
}
/**
* Set the icon for the form.
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
*/
public function setIcon(string $icon) {
$this->icon = $icon;
}
/**
* Set the URL the form will submit to.
* @param string $action
*/
public function setAction(string $action) {
$this->action = $action;
}
/**
* Set the form submission method (GET, POST, etc)
* @param string $method
*/
public function setMethod(string $method = "POST") {
$this->method = $method;
}
/**
* Set the form ID.
* @param string $id
*/
public function setID(string $id = "editform") {
$this->id = $id;
}
/**
* Add an input to the form.
*
* @param string $name Element name
* @param string $value Element value
* @param string $type Input type (text, number, date, select, tel...)
* @param bool $required If the element is required for form submission.
* @param string $id Element ID
* @param array $options Array of [value => text] pairs for a select element
* @param string $label Text label to display near the input
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
* @param int $width Bootstrap column width for the input, out of 12.
* @param int $minlength Minimum number of characters for the input.
* @param int $maxlength Maximum number of characters for the input.
* @param string $pattern Regex pattern for custom client-side validation.
* @param string $error Message to show if the input doesn't validate.
*/
public function addInput(string $name, string $value = "", string $type = "text", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4, int $minlength = 1, int $maxlength = 100, string $pattern = "", string $error = "") {
$item = [
"name" => $name,
"value" => $value,
"type" => $type,
"required" => $required,
"label" => $label,
"icon" => $icon,
"width" => $width,
"minlength" => $minlength,
"maxlength" => $maxlength
];
if (!empty($id)) {
$item["id"] = $id;
}
if (!empty($options) & & $type == "select") {
$item["options"] = $options;
}
if (!empty($pattern)) {
$item["pattern"] = $pattern;
}
if (!empty($error)) {
$item["error"] = $error;
}
$this->items[] = $item;
}
/**
* Add a text input.
*
* @param string $name Element name
* @param string $value Element value
* @param bool $required If the element is required for form submission.
* @param string $id Element ID
* @param string $label Text label to display near the input
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
* @param int $width Bootstrap column width for the input, out of 12.
* @param int $minlength Minimum number of characters for the input.
* @param int $maxlength Maximum number of characters for the input.
* @param string $pattern Regex pattern for custom client-side validation.
* @param string $error Message to show if the input doesn't validate.
*/
public function addTextInput(string $name, string $value = "", bool $required = true, string $id = "", string $label = "", string $icon = "", int $width = 4, int $minlength = 1, int $maxlength = 100, string $pattern = "", string $error = "") {
$this->addInput($name, $value, "text", $required, $id, null, $label, $icon, $width, $minlength, $maxlength, $pattern, $error);
}
/**
* Add a select dropdown.
*
* @param string $name Element name
* @param string $value Element value
* @param bool $required If the element is required for form submission.
* @param string $id Element ID
* @param array $options Array of [value => text] pairs for a select element
* @param string $label Text label to display near the input
* @param string $icon FontAwesome icon (example: "fas fa-toilet-paper")
* @param int $width Bootstrap column width for the input, out of 12.
*/
public function addSelect(string $name, string $value = "", bool $required = true, string $id = null, array $options = null, string $label = "", string $icon = "", int $width = 4) {
$this->addInput($name, $value, "select", $required, $id, $options, $label, $icon, $width);
}
/**
* Add a button to the form.
*
* @param string $text Text string to show on the button.
* @param string $icon FontAwesome icon to show next to the text.
* @param string $href If not null, the button will actually be a hyperlink.
* @param string $type Usually "button" or "submit". Ignored if $href is set.
* @param string $id The element ID.
* @param string $name The element name for the button.
* @param string $value The form value for the button. Ignored if $name is null.
* @param string $class The CSS classes for the button, if a standard success-colored one isn't right.
*/
public function addButton(string $text, string $icon = "", string $href = null, string $type = "button", string $id = null, string $name = null, string $value = "", string $class = "btn btn-success") {
$button = [
"text" => $text,
"icon" => $icon,
"class" => $class,
"type" => $type,
"id" => $id,
"href" => $href,
"name" => $name,
"value" => $value
];
$this->buttons[] = $button;
}
/**
* Add a hidden input.
* @param string $name
* @param string $value
*/
public function addHiddenInput(string $name, string $value) {
$this->hiddenitems[$name] = $value;
}
/**
* Generate the form HTML.
* @param bool $echo If false, returns HTML string instead of outputting it.
*/
public function generate(bool $echo = true) {
$html = < < < HTMLTOP
< form action = "$this->action" method = "$this->method" id = "$this->id" >
< div class = "card" >
< h3 class = "card-header d-flex" >
< div >
< i class = "$this->icon" > < / i > $this->title
< / div >
< / h3 >
< div class = "card-body" >
< div class = "row" >
HTMLTOP;
foreach ($this->items as $item) {
$required = $item["required"] ? "required" : "";
$id = empty($item["id"]) ? "" : "id=\"$item[id]\"";
$pattern = empty($item["pattern"]) ? "" : "pattern=\"$item[pattern]\"";
if (empty($item['type'])) {
$item['type'] = "text";
}
$itemhtml = "";
$itemlabel = "";
if ($item['type'] == "textarea") {
$itemlabel = "< label class = \"mb-0\" > < i class = \"$item[icon]\" > < / i > $item[label]:< / label > ";
} else if ($item['type'] != "checkbox") {
$itemlabel = "< label class = \"mb-0\" > $item[label]:< / label > ";
}
$strippedlabel = strip_tags($item['label']);
$itemhtml .= < < < ITEMTOP
\n\n < div class = "col-12 col-md-$item[width]" >
< div class = "form-group mb-3" >
$itemlabel
ITEMTOP;
$inputgrouptop = < < < INPUTG
\n < div class = "input-group" >
< div class = "input-group-prepend" >
< span class = "input-group-text" > < i class = "$item[icon]" > < / i > < / span >
< / div >
INPUTG;
switch ($item['type']) {
case "select":
$itemhtml .= $inputgrouptop;
$itemhtml .= < < < SELECT
\n < select class = "form-control" name = "$item[name]" aria-label = "$strippedlabel" $ required >
SELECT;
foreach ($item['options'] as $value => $label) {
$selected = "";
if (!empty($item['value']) & & $value == $item['value']) {
$selected = " selected";
}
$itemhtml .= "\n < option value = \"$value\"$selected > $label< / option > ";
}
$itemhtml .= "\n < / select > ";
break;
case "checkbox":
$itemhtml .= $inputgrouptop;
$itemhtml .= < < < CHECKBOX
\n < div class = "form-group form-check" >
< input type = "checkbox" name = "$item[name]" $ id class = "form-check-input" value = "$item[value]" $ required aria-label = "$strippedlabel" >
< label class = "form-check-label" > $item[label]< / label >
< / div >
CHECKBOX;
break;
case "textarea":
$val = htmlentities($item['value']);
$itemhtml .= < < < TEXTAREA
\n < textarea class = "form-control" id = "info" name = "$item[name]" aria-label = "$strippedlabel" minlength = "$item[minlength]" maxlength = "$item[maxlength]" $ required > $val< / textarea >
TEXTAREA;
break;
default:
$itemhtml .= $inputgrouptop;
$itemhtml .= < < < INPUT
\n < input type = "$item[type]" name = "$item[name]" $ id class = "form-control" aria-label = "$strippedlabel" minlength = "$item[minlength]" maxlength = "$item[maxlength]" $ pattern value = "$item[value]" $ required / >
INPUT;
break;
}
if (!empty($item["error"])) {
$itemhtml .= < < < ERROR
\n < div class = "invalid-feedback" >
$item[error]
< / div >
ERROR;
}
if ($item["type"] != "textarea") {
$itemhtml .= "\n < / div > ";
}
$itemhtml .= < < < ITEMBOTTOM
\n < / div >
< / div > \n
ITEMBOTTOM;
$html .= $itemhtml;
}
$html .= < < < HTMLBOTTOM
< / div >
< / div >
HTMLBOTTOM;
if (!empty($this->buttons)) {
$html .= "\n < div class = \"card-footer d-flex \ " > ";
foreach ($this->buttons as $btn) {
$btnhtml = "";
$inner = "< i class = \"$btn[icon]\" > < / i > $btn[text]";
$id = empty($btn['id']) ? "" : "id=\"$btn[id]\"";
if (!empty($btn['href'])) {
$btnhtml = "< a href = \"$btn[href]\" class = \"$btn[class]\" $ id > $inner< / a > ";
} else {
$name = empty($btn['name']) ? "" : "name=\"$btn[name]\"";
$value = (!empty($btn['name']) & & !empty($btn['value'])) ? "value=\"$btn[value]\"" : "";
$btnhtml = "< button type = \"$btn[type]\" class = \"$btn[class]\" $ id $ name $ value > $inner< / button > ";
}
$html .= "\n $btnhtml";
}
$html .= "\n < / div > ";
}
$html .= "\n < / div > ";
foreach ($this->hiddenitems as $name => $value) {
$value = htmlentities($value);
$html .= "\n < input type = \"hidden\" name = \"$name\" value = \"$value\" / > ";
}
$html .= "\n< / form > \n";
if ($echo) {
echo $html;
}
return $html;
}
}