Commit d78513ea authored by Carsten  Rose's avatar Carsten Rose
Browse files

AbstractBuildForm: new getColumnSize() - retrieve size limit for a column from...

AbstractBuildForm: new getColumnSize() - retrieve size limit for a column from the table definitiom. $formElement['maxLength'] will be checked against the max physical size and adjusted where necessary. Implemented 'tooltip' as a title tag. All rendered HTML Attributes are now trimmed. getInputCheckPattern(): fixed a bug and new check if min|max are set. Renamed extractKeyValueList() to getKeyValueListFromSqlEnumSpec().
BuildFormPlainTest: new
parent f41ce78d
......@@ -340,6 +340,18 @@ abstract class AbstractBuildForm {
$attribute = $this->getAttribute('name', $htmlFormElementId);
$htmlTag = '<input';
// MIN( $formElement['maxLength'], tabledefinition)
$maxLength = $this->getColumnSize($formElement['name']);
if ($maxLength !== false) {
if (is_numeric($formElement['maxLength'])) {
if ($formElement['maxLength'] > $maxLength) {
$formElement['maxLength'] = $maxLength;
}
} else {
$formElement['maxLength'] = $maxLength;
}
}
// Check for input type 'textarea'
$colsRows = explode(',', $formElement['size'], 2);
if (count($colsRows) === 2) {
......@@ -354,21 +366,21 @@ abstract class AbstractBuildForm {
// <input>
if ($formElement['maxLength'] > 0) {
$value = substr($value, 0, $formElement['maxLength']);
$attribute .= $this->getAttributeList($formElement, ['type', 'size', 'maxLength']);
$attribute .= $this->getAttribute('value', htmlentities($value), false);
}
$attribute .= $this->getAttributeList($formElement, ['type', 'size', 'maxLength']);
$attribute .= $this->getAttribute('value', htmlentities($value), false);
}
// 'maxLength' needs an upper 'L': naming convention for DB tables!
$attribute .= $this->getAttributeList($formElement, ['autocomplete', 'autofocus', 'placeholder']);
if ($formElement['type'] === 'email' && $formElement['checkType'] === '')
$formElement['checkType'] = 'email';
$attribute .= $this->getAttribute('title', $formElement['tooltip']);
$attribute .= $this->getInputCheckPattern($formElement['checkType'], $formElement['checkPattern']);
$attribute .= $this->getAttributeMode($formElement);
return "$htmlTag $attribute>$textarea";
}
/**
......@@ -383,7 +395,24 @@ abstract class AbstractBuildForm {
if ($flagOmitEmpty && $value === "")
return '';
return "$type=\"$value\" ";
return $type . '="' . trim($value) . '" ';
}
/**
* @param $column
* @return bool|int|string
*/
private function getColumnSize($column) {
$matches = array();
$typeSpec = $this->store->getVar($column, STORE_TABLE_COLUMN_TYPES);
if (1 === preg_match('/\((.+)\)/', $typeSpec, $matches)) {
if (is_numeric($matches[1]))
return $matches[1];
}
return false;
}
/**
......@@ -420,6 +449,7 @@ abstract class AbstractBuildForm {
* @param $type
* @param $data
* @return string
* @throws \qfq\UserException
*/
private function getInputCheckPattern($type, $data) {
if ($type === '') {
......@@ -428,16 +458,20 @@ abstract class AbstractBuildForm {
$attribute = '';
$arrAttr = explode("|", $type);
$arrAttr = explode("|", $this->inputCheckPattern[$type]);
$arrData = explode("|", $data);
for ($ii = 0; $ii < count($arrAttr); $ii++) {
if ($arrAttr[$ii])
$attribute .= str_replace('%s', $arrData[$ii], $arrAttr[$ii]) . ' ';
if ($arrAttr[$ii]) {
if (!isset($arrData[$ii]))
throw new UserException("Missing MIN|MAX values", ERROR_MISSING_MIN_MAX);
$attribute .= str_replace('%s', trim($arrData[$ii]), $arrAttr[$ii]) . ' ';
}
}
return $attribute;
}
/**
* Set corresponding html attributes readonly/required/disabled, based on $formElement['mode'].
*
......@@ -491,7 +525,7 @@ abstract class AbstractBuildForm {
$itemValue = array();
// Fill $itemKey & $itemValue
$this->extractKeyValueList($formElement, $itemKey, $itemValue);
$this->getKeyValueListFromSqlEnumSpec($formElement, $itemKey, $itemValue);
// Get fallback, if 'checkBoxMode' is not defined:
if (!isset($formElement['checkBoxMode'])) {
......@@ -536,13 +570,17 @@ abstract class AbstractBuildForm {
* @param array $formElement
* @param $itemKey
* @param $itemValue
* @throws UserException
* @throws CodeException
* @throws \qfq\UserException
*/
private function extractKeyValueList(array $formElement, &$itemKey, &$itemValue) {
public function getKeyValueListFromSqlEnumSpec(array $formElement, &$itemKey, &$itemValue) {
$fieldType = '';
$itemKey = array();
$itemValue = array();
if (count($formElement) < 20)
throw new CodeException("Invalid (none or to small) Formelement", ERROR_MISSING_FORMELEMENT);
$itemValue = $this->getItemsForEnumOrSet($formElement['name'], $fieldType);
if (is_array($formElement['sql1'])) {
......@@ -562,12 +600,10 @@ abstract class AbstractBuildForm {
$itemValue = array_column($formElement['sql1'], $keys[$idx]);
}
}
} elseif (isset($formElement['itemList'])) {
if (count($formElement['itemList']) > 0) {
$arr = KeyValueStringParser::parse($formElement['itemList'], ':', ',', IF_VALUE_EMPTY_COPY_KEY);
$itemValue = array_values($arr);
$itemKey = array_keys($arr);
}
} elseif (isset($formElement['itemList']) && strlen($formElement['itemList']) > 0) {
$arr = KeyValueStringParser::parse($formElement['itemList'], ':', ',', IF_VALUE_EMPTY_COPY_KEY);
$itemValue = array_values($arr);
$itemKey = array_keys($arr);
} elseif ($fieldType === 'enum' || $fieldType === 'set') {
// already done at the beginning with '$this->getItemsForEnumOrSet($formElement['name'], $fieldType);'
} else {
......@@ -787,7 +823,7 @@ abstract class AbstractBuildForm {
$itemValue = array();
// Fill $itemKey & $itemValue
$this->extractKeyValueList($formElement, $itemKey, $itemValue);
$this->getKeyValueListFromSqlEnumSpec($formElement, $itemKey, $itemValue);
$attributeBase = $this->getAttributeMode($formElement);
$attributeBase .= $this->getAttribute('name', $htmlFormElementId);
......@@ -833,7 +869,7 @@ abstract class AbstractBuildForm {
$itemValue = array();
// Fill $itemKey & $itemValue
$this->extractKeyValueList($formElement, $itemKey, $itemValue);
$this->getKeyValueListFromSqlEnumSpec($formElement, $itemKey, $itemValue);
$attribute = $this->getAttributeMode($formElement);
$attribute .= $this->getAttribute('name', $htmlFormElementId);
......
......@@ -108,6 +108,7 @@ const ERROR_LOG_NOT_WRITABLE = 1045;
const ERROR_UNNOWN_STORE = 1046;
const ERROR_GET_STORE_ZERO = 1047;
const ERROR_SET_STORE_ZERO = 1048;
const ERROR_MISSING_FORMELEMENT = 1049;
// DB Errors
......
<?php
require_once(__DIR__ . '/../../qfq/BuildFormPlain.php');
require_once(__DIR__ . '/../../qfq/Form.php');
require_once(__DIR__ . '/AbstractDatabaseTest.php');
/**
* Created by PhpStorm.
* User: crose
* Date: 2/2/16
* Time: 10:07 PM
*/
class BuildFormPlainTest extends AbstractDatabaseTest {
// private $form;
public function testGetProcessFilter() {
$build = new \qfq\BuildFormPlain(array(), array(), array());
$this->assertEquals(FORM_ELEMENTS_NATIVE, $build->getProcessFilter());
}
public function testWrapItem() {
$build = new \qfq\BuildFormPlain(array(), array(), array());
$result = $build->wrapItem(WRAP_SETUP_ELEMENT, 'Hello World', false);
$this->assertEquals('<p>Hello World</p>', $result);
$result = $build->wrapItem(WRAP_SETUP_ELEMENT, 'Hello World', true);
$this->assertEquals('<p>Hello World</p>', $result);
$result = $build->wrapItem(WRAP_SETUP_ELEMENT, '', false);
$this->assertEquals('<p></p>', $result);
$result = $build->wrapItem(WRAP_SETUP_ELEMENT, '', true);
$this->assertEquals('', $result);
}
public function testWrapTag() {
$build = new \qfq\BuildFormPlain(array(), array(), array());
$result = $build->wrapTag("<p class='test'>", 'Hello World', false);
$this->assertEquals("<p class='test'>Hello World</p>", $result);
$result = $build->wrapTag("<p class='test'>", 'Hello World', true);
$this->assertEquals("<p class='test'>Hello World</p>", $result);
$result = $build->wrapTag("<p class='test'>", '', false);
$this->assertEquals("<p class='test'></p>", $result);
$result = $build->wrapTag("<p class='test'>", '', true);
$this->assertEquals('', $result);
}
public function testBuildLabel() {
$build = new \qfq\BuildFormPlain(array(), array(), array());
$result = $build->buildLabel('myLabel:123', "Hello World");
$this->assertEquals('<label for="myLabel:123">Hello World</label>', $result);
}
public function testBuildInput() {
$form = array();
$formElement = array();
$this->setFormFormElement($form, $formElement);
$build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
// $formElement = $this->db->sql("SELECT * FROM FormElement AS fe WHERE fe.id=114", ROW_EXACT_1);
// $this->assertEquals('', $formElement);
// $formElement = [
// 'id' => 123,
// 'formId' => 2,
// 'feIdContainer' => 0,
// 'enabled' => 'yes',
// 'name' => 'name',
// 'label' => 'Name',
// 'mode' => 'show',
// 'class' => 'native',
// 'type' => 'input',
// 'value' => '',
// 'sql1' => '',
// 'parameter' => '',
// 'debug' => 'no',
// 'deleted' => 'no',
//
// 'size' => '',
// 'maxLength' => '',
// 'tooltip' => '',
// 'placeholder' => '',
// 'checkType' => '',
// 'checkPattern' => '',
//
// 'tabindex' => 0
// ];
// Defaults
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" maxlength="255" value="" >', $result);
// CheckType
$formElement['checkType'] = 'min|max';
$formElement['checkPattern'] = '1|10';
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" maxlength="255" value="" min="1" max="10" >', $result);
$formElement['checkType'] = 'pattern';
$formElement['checkPattern'] = '^[a-z]*$';
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" maxlength="255" value="" pattern="^[a-z]*$" >', $result);
$formElement['checkType'] = 'number';
$formElement['checkPattern'] = '';
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" maxlength="255" value="" pattern="^[0-9]*$" >', $result);
$formElement['checkType'] = 'email';
$formElement['checkPattern'] = '';
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" maxlength="255" value="" pattern="^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$" >', $result);
$formElement['checkType'] = '';
$formElement['checkPattern'] = '';
// Explizit size
$formElement['size'] = 40;
$formElement['maxLength'] = 40;
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" size="40" maxlength="40" value="" >', $result);
// maxlength bigger than physical spec:
$formElement['maxLength'] = 1000;
$result = $build->buildInput($formElement, 'name:1', '');
$this->assertEquals('<input name="name:1" type="input" size="40" maxlength="255" value="" >', $result);
// Explicit: further
$formElement['tooltip'] = 'Nice Tooltip';
$formElement['placeholder'] = 'Please type a name';
$result = $build->buildInput($formElement, 'name:1', 'Hello World');
$this->assertEquals('<input name="name:1" type="input" size="40" maxlength="255" value="Hello World" placeholder="Please type a name" title="Nice Tooltip" >', $result);
// textarea
$formElement['size'] = '40,10';
$result = $build->buildInput($formElement, 'name:1', 'Hello World');
$this->assertEquals('<textarea name="name:1" cols="40" rows="10" placeholder="Please type a name" title="Nice Tooltip" >Hello World</textarea>', $result);
$formElement['size'] = ' 40 , 10 ';
$result = $build->buildInput($formElement, 'name:1', 'Hello World');
$this->assertEquals('<textarea name="name:1" cols="40" rows="10" placeholder="Please type a name" title="Nice Tooltip" >Hello World</textarea>', $result);
}
private function setFormFormElement(array &$form, array &$formElement) {
$form = [
'id' => '1',
'name' => 'form',
'title' => 'Form Editor: {{SELECT id, " / ", title FROM Form WHERE id => {{recordId:S0}}}}',
'noteInternal' => 'Please secure the form',
'tableName' => 'Form',
'permitNew' => 'always',
'permitEdit' => 'always',
'permitUrlParameter' => '',
'render' => 'bootstrap',
'multiMode' => 'none',
'multiSql' => '',
'multiDetailForm' => '',
'multiDetailFormParameter' => '',
'forwardMode' => 'auto',
'forwardPage' => '',
'bsLabelColumns' => '',
'bsInputColumns' => '',
'bsNoteColumns' => '',
'parameter' => 'maxVisiblePill=>3',
'deleted' => 'no'
];
$formElement = [
'id' => 123,
'formId' => 1,
'feIdContainer' => 0,
'enabled' => 'yes',
'name' => 'name',
'label' => 'Name',
'mode' => 'show',
'class' => 'native',
'type' => 'input',
'value' => '',
'sql1' => '',
'parameter' => '',
'debug' => 'no',
'deleted' => 'no',
'size' => '',
'maxLength' => '',
'tooltip' => '',
'placeholder' => '',
'checkType' => '',
'checkPattern' => '',
'tabindex' => 0
];
}
/**
* @expectedException \qfq\UserException
*
*/
public function testBuildInputException() {
$form = array();
$formElement = array();
$this->setFormFormElement($form, $formElement);
$build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
$formElement['checkType'] = 'min|max';
$formElement['checkPattern'] = '';
$result = $build->buildInput($formElement, 'name:1', '');
}
public function testGetKeyValueListFromSqlEnumSpec() {
$form = array();
$formElement = array();
$this->setFormFormElement($form, $formElement);
$formElement['name'] = 'deleted';
$build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
$keys = array();
$values = array();
// Spec Enum
$expect = ['yes', 'no'];
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
// Spec Enum + emptyItemAtStart
$expect = ['', 'yes', 'no'];
$formElement['emptyItemAtStart'] = '';
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
// Spec Enum + emptyItemAtEnd
$expect = ['', 'yes', 'no', ''];
$formElement['emptyItemAtEnd'] = '';
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
// clean
unset($formElement['emptyItemAtStart']);
unset($formElement['emptyItemAtEnd']);
// listItem: only value
$expect = ['a', 'b', 'c'];
$formElement['itemList'] = 'a,b,c';
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
// listItem: key/value
$expectKeys = ['A', 'B', 'C'];
$expectValues = ['a', 'b', 'c'];
$formElement['itemList'] = 'A:a,B:b,C:c';
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expectKeys, $keys);
$this->assertEquals($expectValues, $values);
// listItem: key/value + emptyItemAtEnd
$formElement['emptyItemAtEnd'] = '';
$expectKeys = ['A', 'B', 'C', ''];
$expectValues = ['a', 'b', 'c', ''];
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expectKeys, $keys);
$this->assertEquals($expectValues, $values);
unset($formElement['emptyItemAtEnd']);
// SQL
$formElement['sql1'] = $this->db->sql('SELECT name FROM Form AS f ORDER BY f.id LIMIT 3');
$expect = ['form', 'formElement', 'phpunit_person'];
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
// SQL (one column, no keyword) + emptyItemAtStart
$formElement['emptyItemAtStart'] = '';
$formElement['sql1'] = $this->db->sql('SELECT name FROM Form AS f ORDER BY f.id LIMIT 3');
$expect = ['', 'form', 'formElement', 'phpunit_person'];
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expect, $keys);
$this->assertEquals($expect, $values);
unset($formElement['emptyItemAtStart']);
// SQL (4 columns, none 'id' nor 'label') - Take the first two columns
$expectKeys = ['10', '20', '30'];
$expectValues = ['basic', 'permission', 'various'];
$formElement['sql1'] = $this->db->sql('SELECT ord, name, created, modified FROM FormElement AS fe ORDER BY fe.id LIMIT 3');
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expectKeys, $keys);
$this->assertEquals($expectValues, $values);
// SQL (4 columns, none 'id', one 'label' ) - Take the first and the fourth two columns
$expectKeys = ['10', '20', '30'];
$expectValues = ['basic', 'permission', 'various'];
$formElement['sql1'] = $this->db->sql('SELECT ord, created, modified, name AS label FROM FormElement AS fe ORDER BY fe.id LIMIT 3');
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expectKeys, $keys);
$this->assertEquals($expectValues, $values);
// SQL (4 columns, none 'id', one 'label' ) - Take the first and the fourth two columns
$expectKeys = ['1', '2', '3'];
$expectValues = ['basic', 'permission', 'various'];
$formElement['sql1'] = $this->db->sql('SELECT ord, created, modified, name AS label, id FROM FormElement AS fe ORDER BY fe.id LIMIT 3');
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
$this->assertEquals($expectKeys, $keys);
$this->assertEquals($expectValues, $values);
}
/**
* @expectedException \qfq\UserException
*
*/
public function testGetKeyValueListFromSqlEnumSpecException() {
$form = array();
$formElement = array();
$this->setFormFormElement($form, $formElement);
$build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
$formElement['name'] = 'noteInternal';
$build->getKeyValueListFromSqlEnumSpec($formElement, $keys, $values);
}
public function ttttestBuildCheckbox() {
// $formElement = [
// 'id' => 123,
// 'formId' => 2,
// 'feIdContainer' => 0,
// 'enabled' => 'yes',
// 'name' => 'type',
// 'label' => 'Type',
// 'mode' => 'show',
// 'class' => 'native',
// 'type' => 'radio',
// 'value' => '',
// 'sql1' => '',
// 'parameter' => '',
// 'debug' => 'no',
// 'deleted' => 'no',
//
// 'size' => '',
// 'maxLength' => '',
// 'tooltip' => '',
// 'placeholder' => '',
// 'checkType' => '',
// 'checkPattern' => '',
//
// 'tabindex' => 0
// ];
$form = array();
$formElement = array();
$this->setFormFormElement($form, $formElement);
$build = new \qfq\BuildFormPlain($form, array(), [$formElement]);
$formElement['checkType'] = 'min|max';
$formElement['checkPattern'] = '';
$result = $build->buildInput($formElement, 'name:1', '');
}
/**
* @throws Exception
*/
protected function setUp() {
$_GET['form'] = 'phpunit_person';
parent::setUp();
$this->executeSQLFile(__DIR__ . '/fixtures/Generic.sql', true);
// $this->executeSQLFile(__DIR__ . '/fixtures/TestFormEditor.sql', true);
$this->form = new \qfq\Form("form=form\nr=3", true);
// this is necessary to initialize SIP
$content = $this->form->process();
}
}
DROP TABLE IF EXISTS `Form`;
CREATE TABLE IF NOT EXISTS `Form` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL DEFAULT '',
`title` VARCHAR(255) NOT NULL DEFAULT '',
`noteInternal` TEXT NOT NULL,
`tableName` VARCHAR(255) NOT NULL DEFAULT '',
`permitNew` ENUM('sip', 'logged_in', 'logged_out', 'always', 'never') NOT NULL DEFAULT 'sip',
`permitEdit` ENUM('sip', 'logged_in', 'logged_out', 'always', 'never') NOT NULL DEFAULT 'sip',
`permitUrlParameter` VARCHAR(255) NOT NULL DEFAULT '',
`render` ENUM('plain', 'table', 'bootstrap') NOT NULL DEFAULT 'plain',
`multiMode` ENUM('none', 'horizontal', 'vertical') NOT NULL DEFAULT 'none',
`multiSql` TEXT NOT NULL,
`multiDetailForm` VARCHAR(255) NOT NULL DEFAULT '',
`multiDetailFormParameter` VARCHAR(255) NOT NULL DEFAULT '',
`forwardMode` ENUM('auto', 'no', 'page') NOT NULL DEFAULT 'auto',
`forwardPage` VARCHAR(255) NOT NULL DEFAULT '',
`bsLabelColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsInputColumns` VARCHAR(255) NOT NULL DEFAULT '',
`bsNoteColumns` VARCHAR(255) NOT NULL DEFAULT '',
`parameter` TEXT NOT NULL,
`deleted` ENUM('yes', 'no') NOT NULL DEFAULT 'no',
`modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,