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

UsersManual/index.rst: Updated 'action'-FormElement description. Startet to write examples.

FormAction.php: initialize action formelements. ExpectRecords might specified as a list. After an insert, set slaveId to latest id. Process sqlDelete if given.
Store.php: STORE_VAR and STORE_EMPTY missed to configure for Sanatize.
QuickFormQuery.php: Initialized after the form is loaded.
parent 433e3b05
......@@ -950,12 +950,13 @@ Types:
* ‘’‘requiredList‘’‘ - List of `native`-FormElements: only if all of those elements are filled, the current
`action`-FormElement will be processed.
* ‘’‘sqlValidate’‘’ - query. E.g.: `sqlValidate={{!SELECT id FROM Person AS p WHERE p.name LIKE {{name:F}} AND p.firstname LIKE {{firstname:F}} }}`
* ‘’‘sqlValidate’‘’ - query. E.g.: `sqlValidate={{!SELECT id FROM Person AS p WHERE p.name LIKE {{name:F:all}} AND p.firstname LIKE {{firstname:F:all}} }}`
* Pay attention to '{{!...' after the equal sign.
* ‘’‘expectRecords‘’‘ - number of records. E.g.: `expectRecords=0`
* ‘’‘messageFail‘’‘ - Message to show. E.g.: `messageFail=There is already a person called {{firstname:F}} {{name:F}}`
* ‘’‘expectRecords‘’‘ - number of records. E.g.: `expectRecords=0` or `expectRecords=0,1` or `expectRecords={{SELECT COUNT(id) FROM Person}}`
* Separate multiple valid record numbers by ','. If at least one of those matches, the check will pass successfully.
* ‘’‘messageFail‘’‘ - Message to show. E.g.: `messageFail=There is already a person called {{firstname:F:all}} {{name:F:all}}`
* Insert / Update / Delete records
......@@ -977,7 +978,7 @@ Types:
* ‘’‘sqlUpdate‘’‘ - query. E.g.: `sqlUpdate={{UPDATE Address SET street = '{{street:F:all}}' WHERE id={{slaveId:V}} LIMIT 1}}`
* ‘’‘sqlInsert‘’‘ - query. E.g.: `sqlInsert={{INSERT INTO Address (pId, street) VALUES ( {{id:R}}, '{{street:F:all}}' WHERE id={{slaveId:V}} }}`
* ‘’‘sqlDelete‘’‘ - query: NOT IMPLEMENTED. Will be usefull for MultiForms.
* ‘’‘sqlDelete‘’‘ - query: E.g.: `sqlDelete={{DELETE FROM Address WHERE id={{slaveId:V}} AND ''='{{city:F:allbut:s}}' LIMIT 1}}`
* If the `action`-FormElement name exist as a column in the master record: Update that column with the recent slaveId
(after an INSERT the last_insert_id() acts as the new `slaveId`).
......@@ -2366,12 +2367,44 @@ Compute the next 'ord' as default value direct inside the secondary form. No cha
Form: Person Wizard
-------------------
Requirement: A form that displays the column 'firstname' from table 'Person' and 'email' from table 'Address'. If the
Requirement: A form that displays the column 'firstname' from table 'Person' and 'city' from table 'Address'. If the
records not exist, the form should create it.
* Form
Form primary table: Person
Form salve table: Address
Relation: Person.id = Address.personId
* Form: wizard
* Name: wizard
* Titile: Person Wizard
* Table: Person
* Render: bootsrap
\ No newline at end of file
* Render: bootstrap
* FormElement: firstname
* Name: firstname
* Label: Firstname
* Class: native
* Type: text
* FormElement: email, text, 20
* Name: city
* Label: City
* Value: {{SELECT city FROM Address WHERE personId={{r}} ORDER BY id LIMIT 1}}
* Class: native
* Type: text
* FormElement: insert/update address record
* Label: Manage Address
* Class: action
* Type: afterSave
* Parameter:
* slaveId={{SELECT id FROM Address WHERE personId={{r}} ORDER BY id LIMIT 1}}
* sqlInsert={{INSERT INTO Address (personId, city) VALUES ({{r}}, '{{city:F:allbut:s}}') }}
* sqlUpdate={{UPDATE Address SET city='{{city:F:allbut:s}}' WHERE id={{slaveId:V}} }}
* sqlDelete={{DELETE FROM Address WHERE id={{slaveId:V}} AND ''='{{city:F:allbut:s}}' LIMIT 1}}
......@@ -212,7 +212,6 @@ class QuickFormQuery {
private function doForm($mode) {
$data = '';
$foundInStore = '';
$formAction = new formAction($this->formSpec, $this->db, $this->phpUnit);
// Fill STORE_FORM
if ($mode === FORM_UPDATE || $mode === FORM_SAVE) {
......@@ -221,14 +220,17 @@ class QuickFormQuery {
}
$formName = $this->loadFormSpecification($mode, $foundInStore);
if ($formName === false)
if ($formName === false) {
return '';
}
$sipFound = $this->validateForm($foundInStore);
if (!$sipFound) {
$this->store->createSipAfterFormLoad($formName);
}
$formAction = new FormAction($this->formSpec, $this->db, $this->phpUnit);
$this->store->fillStoreTableDefaultColumnType($this->formSpec[F_TABLE_NAME]);
switch ($this->formSpec['render']) {
......
......@@ -17,7 +17,7 @@ require_once(__DIR__ . '/../Evaluate.php');
* Class formAction
* @package qfq
*/
class formAction {
class FormAction {
// private $feSpecNative = array(); // copy of all formElement.class='native' of the loaded form
/**
......@@ -65,15 +65,11 @@ class formAction {
*/
public function elements($recordId, array $feSpecAction, $feTypeList) {
// get current data record
// if ($recordId > 0 && $this->store->getVar('id', STORE_RECORD) === false) {
// $row = $this->db->sql("SELECT * FROM " . $this->formSpec[F_TABLE_NAME] . " WHERE id = ?", ROW_EXPECT_1, array($recordId));
// $this->store->setVarArray($row, STORE_RECORD);
// }
// Iterate over all Action FormElements
foreach ($feSpecAction as $fe) {
$fe = $this->initActionFormElement($fe);
if (false === Support::findInSet($fe[FE_TYPE], $feTypeList)) {
continue;
}
......@@ -96,6 +92,20 @@ class formAction {
}
}
/**
* Set all necessary keys
*
* @param array $fe
* @return array
*/
private function initActionFormElement(array $fe) {
$list = [FE_TYPE, FE_SLAVE_ID, FE_SQL_VALIDATE, FE_SQL_INSERT, FE_SQL_UPDATE, FE_SQL_DELETE, FE_EXPECT_RECORDS, FE_REQUIRED_LIST, FE_MESSAGE_FAIL];
foreach ($list as $key) {
Support::setIfNotSet($fe, $key);
}
return $fe;
}
/**
* @param $table
* @param $recordId
......@@ -146,7 +156,7 @@ class formAction {
* If there is a query defined in fe.parameter.FE_SQL_VALIDATE: fire them.
* Count the selected records and compare them with fe.parameter.FE_EXPECT_RECORDS.
* If match: everything is fine, do nothing.
* Else throw the error message in fe.parameter.FE_MESSAGE_FAIL
* Else throw UserFormException with error message of fe.parameter.FE_MESSAGE_FAIL
*
* @param array $fe
* @throws UserFormException
......@@ -154,14 +164,13 @@ class formAction {
private function validate(array $fe) {
// Is there something to check?
if (Support::setIfNotSet($fe, FE_SQL_VALIDATE) === '') {
if ($fe[FE_SQL_VALIDATE] === '') {
return;
}
$expect = Support::setIfNotSet($fe, FE_EXPECT_RECORDS, '0');
$expect = $this->evaluate->parse($fe[FE_EXPECT_RECORDS]);
$msg = Support::setIfNotSet($fe, FE_MESSAGE_FAIL);
if ($msg === '') {
if ($fe[FE_MESSAGE_FAIL] === '') {
throw new UserFormException("Missing error message. Column: " . FE_MESSAGE_FAIL, ERROR_MISSING_MESSAGE_FAIL);
}
......@@ -171,11 +180,15 @@ class formAction {
throw new UserFormException("Expected an array for '" . FE_SQL_VALIDATE . "', got a scalar. Please check for {{!...", ERROR_EXPECTED_ARRAY);
}
if (count($result) == $expect) {
return; // check succesfully passed
// If there is at least one record count given, who matches: return 'check succeeded'
$countRecordsArr = explode(',', $expect);
foreach ($countRecordsArr AS $count) {
if (count($result) == $count) {
return; // check succesfully passed
}
}
$msg = $this->evaluate->parse($msg); // Replace possible dynamic parts
$msg = $this->evaluate->parse($fe[FE_MESSAGE_FAIL]); // Replace possible dynamic parts
// Throw user defineable error message
throw new UserFormException($msg, ERROR_REPORT_FAILED_ACTION);
......@@ -193,8 +206,7 @@ class formAction {
$flagUpdateMasterRecord = false;
// Get the slaveId
$tmp = Support::setIfNotSet($fe, FE_SLAVE_ID);
$slaveId = $this->evaluate->parse($tmp);
$slaveId = $this->evaluate->parse($fe[FE_SLAVE_ID]);
if ($slaveId === '' && $fe[FE_NAME] !== '') {
// if the current action element has the same name as a real master record column: take that value as an id
......@@ -211,6 +223,8 @@ class formAction {
// Fire slave query
if ($slaveId == 0) {
$slaveId = $this->evaluate->parse($fe[FE_SQL_INSERT]);
// Store the slaveId: it's used and replaced in the update statement.
$this->store->setVar(ACTION_KEYWORD_SLAVE_ID, $slaveId, STORE_VAR, true);
} else {
$this->evaluate->parse($fe[FE_SQL_UPDATE]);
}
......@@ -221,9 +235,11 @@ class formAction {
$this->db->sql("UPDATE " . $this->primaryTableName . " SET " . $fe[FE_NAME] . " = $slaveId WHERE id = ? LIMIT 1", ROW_REGULAR, [$recordId]);
}
// If given fire a delete query
$this->evaluate->parse($fe[FE_SQL_DELETE]);
return $slaveId;
}
}
//
///********************************************************
......
......@@ -141,7 +141,9 @@ class Store {
STORE_TABLE_COLUMN_TYPES => false,
STORE_CLIENT => true,
STORE_TYPO3 => false,
STORE_VAR => false,
STORE_ZERO => false,
STORE_EMPTY => false,
STORE_SYSTEM => false,
STORE_EXTRA => false
];
......
......@@ -14,6 +14,7 @@ require_once(__DIR__ . '/../../qfq/exceptions/UserFormException.php');
class BodytextParserTest extends \PHPUnit_Framework_TestCase {
public function testProcessPlain() {
$btp = new BodytextParser();
......
<?php
/**
* Created by PhpStorm.
* User: crose
* Date: 1/15/16
* Time: 8:24 AM
*/
namespace qfq;
//use qfq\Store;
//use qfq;
require_once(__DIR__ . '/AbstractDatabaseTest.php');
require_once(__DIR__ . '/../../qfq/form/FormAction.php');
//require_once(__DIR__ . '/../../qfq/Database.php');
//require_once(__DIR__ . '/../../qfq/store/Store.php');
class FormActionTest extends \AbstractDatabaseTest {
public function testBeforeLoad() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
// Nothing to do: should not throw an exception
$formAction->elements(0, array(), '');
$formAction->elements(0, array(), FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
// Fire sqlValidate with one record, expect 1 record
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 1}}';
$feSpecAction[FE_EXPECT_RECORDS] = '1';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
// Fire sqlValidate with one record, expect 0-2 records
$feSpecAction[FE_EXPECT_RECORDS] = '0,1,2';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
// Fire sqlValidate with one record, expect 0-2 records
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_EXPECT_RECORDS] = '0,1,2';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
// Check with more classes
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_LOAD;
$feSpecAction[FE_EXPECT_RECORDS] = '0,1,2';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD);
}
/**
* Expect 0 recrod, but get 1
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException1() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 1}}';
$feSpecAction[FE_EXPECT_RECORDS] = '0';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
}
/**
* Expect 1 recrod, but get 0
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException0() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 0}}';
$feSpecAction[FE_EXPECT_RECORDS] = '1';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
}
/**
* Expect '0,1', but get 2 records
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException2() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_BEFORE_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '0,1';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD);
}
/**
* Expect '0,1', but get 2 records
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException3() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_UPDATE;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '0,1';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
}
/**
* Necessary FE is empty > don't process check
**/
public function testBeforeLoadException4() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_UPDATE;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '0,1';
// one FE in list
$this->store->setVar('street', 'Street', STORE_FORM, true);
$this->store->setVar('city', '', STORE_FORM, true);
$feSpecAction[FE_REQUIRED_LIST] = 'city';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
// three FE in list. one is set, one not, one dont exist
$this->store->setVar('city', '', STORE_FORM, true);
$feSpecAction[FE_REQUIRED_LIST] = 'street,city,downtown';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
}
/**
* Expect '0,1', but get 2 records
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException5() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$this->store->setVar('city', 'New York', STORE_FORM, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_UPDATE;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '0,1';
$formAction->elements(0, [$feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
}
/**
* Do check for 2 action records
**/
public function testBeforeLoad2() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '2';
$formAction->elements(0, [$feSpecAction, $feSpecAction], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
}
/**
* Do check for 2 action records, fail on second.
* @expectedException \qfq\UserFormException
**/
public function testBeforeLoadException6() {
$formSpec[F_TABLE_NAME] = 'Person';
$formAction = new FormAction($formSpec, $this->db, true);
$feSpecAction[FE_NAME] = '';
$feSpecAction[FE_TYPE] = FE_TYPE_AFTER_LOAD;
$feSpecAction[FE_MESSAGE_FAIL] = 'error';
$feSpecAction[FE_SQL_VALIDATE] = '{{!SELECT id FROM Person LIMIT 2}}';
$feSpecAction[FE_EXPECT_RECORDS] = '2';
$feSpecAction2 = $feSpecAction;
$feSpecAction2[FE_EXPECT_RECORDS] = '0';
$formAction->elements(0, [$feSpecAction, $feSpecAction2], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
}
/**
* Process INSERT
**/
// public function testInsert() {
// $formSpec[F_TABLE_NAME] = 'Person';
// $formAction = new FormAction($formSpec, $this->db, true);
//
// $feSpecAction[FE_NAME] = '';
// $feSpecAction[FE_TYPE] = FE_TYPE_AFTER_SAVE;
// $feSpecAction[FE_SLAVE_ID] = '{{ UPDATE Address SET city="Donwtown" WHERE id={{slaveID:V}} }} ';
// $feSpecAction[FE_SQL_UPDATE] = '{{ UPDATE Address SET city="Donwtown" WHERE id={{slaveID:V}} }} ';
// $formAction->elements(0, [ $feSpecAction, $feSpecAction ], FE_TYPE_BEFORE_LOAD . ',' . FE_TYPE_AFTER_LOAD . ',' . FE_TYPE_AFTER_UPDATE . ',' . FE_TYPE_BEFORE_SAVE);
// }
// public function testBeforeLoad1() {
// $formSpec[F_TABLE_NAME] = 'Person';
// $formAction = new FormAction($formSpec, $this->db, true);
//
//
// // no variable
// $this->assertEquals('nothing', $eval->parse('nothing'));
// $this->assertEquals('TestFormName', $eval->parse('{{form:T}}'));
// }
protected function setUp() {
$this->store = Store::getInstance('form=TestFormName', true);
parent::setUp();
$this->store->setVar('form', 'TestFormName', STORE_TYPO3);
$this->executeSQLFile(__DIR__ . '/fixtures/Generic.sql', true);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment