CODING.md 8.61 KB
Newer Older
Carsten  Rose's avatar
Carsten Rose committed
1
2
Design / Notes / Best Practices for Coding
==========================================
Carsten  Rose's avatar
Carsten Rose committed
3
4
5
6

General
=======

Carsten  Rose's avatar
Carsten Rose committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
* 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
  
Carsten  Rose's avatar
Carsten Rose committed
39
40
* 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.
Carsten  Rose's avatar
Carsten Rose committed
41
  * The Form specificaton (table form) will be evaluated direct after loading.
Carsten  Rose's avatar
Carsten Rose committed
42
43
44
  * The FormElement specification will be evaluated later on in BuildForm*.php


Carsten  Rose's avatar
Carsten Rose committed
45
46
47
48
SAVE
----
* Via wrapper api/save.php
* SID must be supplied via FORM POST
Carsten  Rose's avatar
Carsten Rose committed
49
* The SID supplies the <formname> and the <recordid>
Carsten  Rose's avatar
Carsten Rose committed
50
51
52
53
* form.render: plain/table/bootstrap
  * Client will handle the response of save.php.
  * Optional redirection initiated by client.
  
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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>
  
76
77
78
79
80
81
Upload
-----------------

* The upload UI consist of three elements
  * 1) A <div> tag with a) an optional filename of an earlier uploaded file and b) a trash Button.
  * 2) The 'browse' button (<input type='file' name='<feName>'>). This element will not be send by post.
82
  * 3) A HTML hidden element with name=<feName> containing the <sipUpload>.
83
84
85
86
* A new uniq SIP (sipUpload) will be created for every upload formElement. These 'sipUpload' will be assigned to the upload browse button and to the upload delete button.  
  * The individual sipUpload is necessary to correctly handle multiple simultaenously forms when using r=0. Also, through this uniq id it's easy to distinguish between asynchron uploaded files.
  * The SIP on ther server contains the individual '_FILES' information submitted during the upload.
* Via the hidden element <feName> 'save()', access to the form individual upload status informations is given. 
87
88
89

Upload to server, before 'save'
...............................
90
91
* If a user open's a file for upload via the browse button, that file is immediately transmitted to the server. The user will see a turning wheel during until the upload finished.
* After successfull upload the 'Browse' button disappears and the filename, plus the delete button, will be displayed (client logic). 
92
93
94
95
* The uploaded file will be checked: maxsize, mime type, check script.
* The uploaded file is still temporary. It has been renamed from $_SESSION['X'][<uploadSip>][FILES_TMP_NAME] to  $_SESSION['X'][<uploadSip>][FILES_TMP_NAME].cached
* The upload action will be saved in the user session.
  *  $_SESSION['X'][<uploadSip>][FILES_TMP_NAME|FILES_NAME|FILES_ERROR|FILE_SIZE]
96
* Clicks the user on delete button:
97
98
99
100
101
102
103
104
105
106
107
108
109
  * In the usersession a flagDelete will be set: $_SESSION['X'][<uploadSip>]['flagDelete']='1'
  * An optional previous upload file (still not saved on the final place) will be deleted.
  * An optional existing variable $_SESSION['X'][<uploadSip>][FILES_TMP_NAME] will be deleted. The 'flagDelete' must not be change - it's later needed to detect to delete earlier uploaded files.

Form save
.........
* Before building the insert/update, process all 'uploads'.
* Get every uniq sipUpload to every upload formElement. Get the corresponding temporary uploaded filename.
* If $_SESSION['X'][<uploadSip>]['flagDelete']='1' is set, delete prefious uploaded file.
* Calculate <destination>
* mv <file>.cached <destination>
* clientvalue[<feName>] = <destination>
* delete $_SESSION['X'][<uploadSip>]
110

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
Formelement type: DATE / DATETIME / TIME
----------------------------------------
 * Available Formats:
   * 'yyyy-mm-dd' = FORMAT_DATE_INTERNATIONAL. 
   * 'dd.mm.yyyy' = FORMAT_DATE_GERMAN.
 * The 'DATE_FORMAT' can be specified systemwide in `config.ini`
 * The default format is FORMAT_DATE_INTERNATIONAL.
 * Optional: 'dateFormat' can be specified per form element in `form.parameter` - this overwrites 'systemwide'.
 * If there is no placeholder defined on the form element, the defined dateFormat is shown as placeholder.
 
 * Browser: 
   * checks the input with a system regexp.
   * regexp might be user defined. If given, do not use system regexp!
   * No min/max check.
 * Server: 
   * check with system wirde regexp 
   * regexp might be user defined. If given, do not use system regexp!
   * Do min/max check.
 
 * MySQL data: 1000-01-01 - 9999-12-31 and 0000-00-00
 * MySQL time: 00:00:00 - 23:59:59
 
 * datetime format: 'DATE TIME'

Carsten  Rose's avatar
Carsten Rose committed
135
136
137
138
139
Debug / Log / Errormessages
===========================

* Before firing a SQL or doing processing of an FormElement, set some debugging / error variables:

140
    [src] $this->store->setVar(SYSTEM_SQL_RAW, STORE_SYSTEM)
Carsten  Rose's avatar
Carsten Rose committed
141
142

* Available fields:
143
144
145
146
147
148
149
150
151
152

    <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>
Carsten  Rose's avatar
Carsten Rose committed
153

Carsten  Rose's avatar
Carsten Rose committed
154
155
* Form.debugShowInfo: yes|no will display a tooltip near beside every formelement and show parse/evaluate as tooltip.

156
157
158
159
* Check to display debug info:
 
    $this->store->getVar(SYSTEM_SHOW_DEBUG_INFO, STORE_SYSTEM) === 'yes'

Carsten  Rose's avatar
Carsten Rose committed
160
161
162
Stores
======

163
* Retrieve 'get' or 'post' variables by:
Carsten  Rose's avatar
Carsten Rose committed
164
165
166
167
168
169
170
171
172
173
174
175
176
177

[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.

Carsten  Rose's avatar
Carsten Rose committed
178
179
180

Typo3
=====
Carsten  Rose's avatar
Carsten Rose committed
181
182
183
* PageId: $this->store->getVar(TYPO3_PAGE_ID, STORE_TYPO3)
  * Based on: $GLOBALS["TSFE"]->id   current Page
 
Carsten  Rose's avatar
Carsten Rose committed
184
185
186
187
188
189
190
191
* $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'];

192
193
194
* 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
Carsten  Rose's avatar
Carsten Rose committed
195
196
197
198
199
200
201
202
* 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'
Carsten  Rose's avatar
Carsten Rose committed
203
204


205
206
207
208
209
210
211
212
213
214
FormElement
===========

Checkbox
--------

    <div class="checkbox">
        <label>
            <input type="checkbox">label 1
        </label>
Carsten  Rose's avatar
Carsten Rose committed
215
216
    </div>
    
217