Notes / Best Practices for Coding ================================= General ======= * Class QuickFormQuery is the main entry point called by: * T3 Extension 'QFQ': called once per tt_content-record. 'bodytext' will be transferred to class QuickFormQuery. * The 'bodytext' contains: * Report definiton: 10.sql=SELECT ... * Form definition (explizit): form=Person * <Empty>: do nothing * api/save.php: wrapper to receive AJAX post request and instantiate QuickFormQuery. * api/load.php: not implemented yet. * Wrapper to receive AJAX get requests. * delivers data for jqw grid * delivers data for typeahed fields * delivers data for select list * delivers data for depended (user select/unselect former elements) form elements LOAD ---- * When qfq starts, * (Form) Looking for a formname at: 1. Typo3 Bodytext Element, 2. For the 'SIP' ($_GET['s']) 3. $_GET variables 'form' and 'r' (=recordId) - the parameter 'form' has to be allowed in 'Permit URL Parameter' of the specified form. This means: load the form to check, if it is allowed to load the form!? * If a formname is found, the search stops and the specified form will be processed. * (Report) * Process all <number>.[<number.>].sql statements * Access code variables: * active/valid formname: [$this->store->setVar(SYSTEM_FORM, $formName, STORE_SYSTEM);] * SIP: [$this->store->getVar('form', STORE_SIP)] * All parameters from active SIP: [$this->store->getStore(STORE_SIP)] * Check Contstants.php for known Store members * In QuickFormQuery.php the whole Form will be copied to $this->formSpec and depending on further processing, the elements are available in $this->feNative and $this->feAction. * The Form specificaton (table form) will be evaluated direct after loading. * The FormElement specification will be evaluated later on in BuildForm*.php SAVE ---- * Via wrapper api/save.php * SID must be supplied via FORM POST * The SID supplies the <formname> and the <recordid> * form.render: plain/table/bootstrap * Client will handle the response of save.php. * Optional redirection initiated by client. DELETE ------ * Via wrapper api/delete.php * The element who should dissappear after successfull deleting: class=record * Button: * class=record-delete * Button: data-sip={{SIP}} * Three possible variants with delete links: * Form: main record * HTML Code: <button id="delete-button" type="button" class="btn btn-default navbar-btn" ><span class="glyphicon glyphicon-trash"></span></button> * Form: subrecord, one delete button per record * Report: typially inside a table, but maybe different. * HTML Code: <button type="button" class="record-delete" data-sip={{SIP}} ><span class="glyphicon glyphicon-trash"></span></button> USER INTERFACE ============== Button status ------------- * Form modified: * Buttons enabled: Save, Close, New, Delete * Button disable: - * Form not modified: * Buttons enabled: Close, New, Delete * Button disabled: Save Save Button ----------- * User presses the button * Reset all validation states * Client validates HTML Form * Form is submitted to server * Success: * Show message provided by server * Current formelements and data will be reloaded. * Process server reponse 'redirect': * 'client': No redirect. * 'no': No redirect. * 'url': Redirect to URL * Failure: Happens on communication errors, if data validation fails, form actions fails or saving data fails. * Show error message. * Client: Ignore server reponse 'redirect'. Client stays on current page. Close Button ------------ * User presses the button * Form not modified by user: Client redirects to previous page. * Form modified by user: Ask User 'You have unsaved changes. Do you want to close?' * Yes: Client redirects to previous page. * No: Client stays on current page. * Save & Close: * Client reset all validation states * Client validates HTML Form * Client submits form to server. * Success: Process server response 'redirect': * 'client': Client shows previous page. * 'no': No redirect. * 'url': Redirect to URL * Failure: Happens on communication errors, if data validation fails, form actions fails or saving data fails. * Show error message. * Client: No redirect. Ignore server reponse 'redirect'. Delete Button: Main record -------------------------- * User presses the button. Ask User 'Do you really want to delete the record? * Yes: * Delete record on server. * Process server reponse 'redirect': * 'client': Client redirects to previous page. * 'no': Error message. * 'url': Redirect to URL * No: * Client does not delete record on server. * No redirect. Client stays on current page. New Button ---------- * User presses the button * Form not modified by user: Client redirects to href url. * Form modified by user: Ask User 'You have unsaved changes. Do you want to save first?' * Yes: * Client reset all validation states * Client validates HTML Form * Form is submitted to server * Success: * Client: Ignore server reponse 'redirect'. Client redirects to href url. * Failure: Happens on communication errors, if data validation fails, form actions fails or saving data fails. * Show error message. * Client: Ignore server reponse 'redirect'. Client stays on current page. * No: * Client does not save the modified record. * Client redirects to href url. * Cancel: * Client does not save the modified record. * Client stays on current page. Debug / Log / Errormessages =========================== * Before firing a SQL or doing processing of an FormElement, set some debugging / error variables: [src] $this->store->setVar(SYSTEM_SQL_RAW, STORE_SYSTEM) * Available fields: <code> SYSTEM_SQL_RAW SYSTEM_SQL_FINAL SYSTEM_SQL_COUNT SYSTEM_SQL_PARAM_ARRAY SYSTEM_FORM = CLIENT_FORM; // '<formName> / <formId>' SYSTEM_FORM_ELEMENT = 'formElement'; // '<formElementName> / <formElementeId>' SYSTEM_FORM_ELEMENT_COLUMN = 'formElementColumn'; // '<columnname of current processed formElement>' </code> * Form.debugShowInfo: yes|no will display a tooltip near beside every formelement and show parse/evaluate as tooltip. * Check to display debug info: $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) === 'yes' Stores ====== * Retrieve 'get' or 'post' variables by: [src] $values = $this->store->getStore(STORE_CLIENT) Primary Table ============= * For the primary table all informations are available in STORE_TABLE_DEFAULT and STORE_TABLE_COLUMN_TYPES. * Get all columns of the primary table by [src] array_keys($this->getStore(STORE_TABLE_COLUMN_TYPES)) * Get the recent record in STORE_RECORD and the parent record (multiforms) in STORE_PARENT_RECORD. Typo3 ===== * PageId: $this->store->getVar(TYPO3_PAGE_ID, STORE_TYPO3) * Based on: $GLOBALS["TSFE"]->id current Page * $GLOBALS["TSFE"]->fe_user->user["uid"] fe_user_uid * https://wiki.typo3.org/Extbase_HowTos * Old: $this->cObj->data['bodytext'] * New: $contentObject = $this->configurationManager->getContentObject(); $configuration = $contentObject->data['bodytext']; * Verzeichnisstruktur Extension: https://docs.typo3.org/typo3cms/CoreApiReference/ExtensionArchitecture/FilesAndLocations/Index.html * http://api.typo3.org/ * http://api.typo3.org/typo3cms/62/html/index.html * https://docs.typo3.org/typo3cms/CoreApiReference/Introduction/Index.html SIP === Page loaded: www.example.com?index.php&id=start&s=badcaffee1234&type=2&L=3, with $_SESSION['badcaffee1234'] => 'form=Person&r=1' * $_SESSION[$sip] => <urlparam> >> $_SESSION['badcaffee1234'] => 'form=Person&r=1' * $_SESSION[$urlparam] => <sip> >> $_SESSION['form=Person&r=1'] => 'badcaffee1234' FormElement =========== Checkbox -------- <div class="checkbox"> <label> <input type="checkbox">label 1 </label> </div>