Commit 2e1711a4 authored by Marc Egger's avatar Marc Egger
Browse files

doc move sections into own file and fix warnings

parent 3c16549e
Pipeline #3507 passed with stages
in 4 minutes and 16 seconds
......@@ -2,9 +2,6 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# WARNING: This configuration file is currently not recognized by read the docs and I don't know why.
# Therefore I have made the same configurations on the readthedocs.org settings page.
# Required
version: 2
......@@ -15,7 +12,7 @@ sphinx:
# Optionally build your docs in additional formats such as PDF
formats:
- pdf
# - epub
- epub
# Optionally set the version of Python and requirements required to build your docs
python:
......
.. ==================================================
.. ==================================================
.. ==================================================
.. Header hierarchy
.. ==
.. --
.. ^^
.. ""
.. ;;
.. ,,
..
.. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic*
.. Bold **bold**
.. Code ``text``
.. External Links: `Bootstrap <http://getbootstrap.com/>`_
.. Add Images: .. image:: ../Images/a4.jpg
..
..
.. Admonitions
.. .. note:: .. important:: .. tip:: .. warning::
.. Color: (blue) (orange) (green) (red)
..
.. Definition:
.. some text becomes strong (only one line)
.. description has to indented
.. -*- coding: utf-8 -*- with BOM.
.. include:: Includes.txt
.. _applicationTest:
Application Test
================
With a framework like https://www.seleniumhq.org/ it's possible to play and verify unattended test cases.
To assist such frameworks and to make the tests reliable, an individual tag might be assigned to HTML elements which have to
interact with the test framework.
Form
----
By default every FormElement contains an attribute 'data-reference=<value>', whereas the '<value>' is either the name
of the FormElement or a custom value, defined via 'FormElement.parameter.dataReference=<value>'.
Report
------
Any HTML output can be extended by a tag - that's done by the webmaster. For QFQ generated links, an attribute like
'data-reference' might be injected via token 'A' (attribute). ::
SELECT 'p:personedit&form=person&r=1|b|s|A:data-reference="person-edit"|t:Edit person' AS _link
.. ==================================================
.. ==================================================
.. ==================================================
.. Header hierarchy
.. ==
.. --
.. ^^
.. ""
.. ;;
.. ,,
..
.. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic*
.. Bold **bold**
.. Code ``text``
.. External Links: `Bootstrap <http://getbootstrap.com/>`_
.. Add Images: .. image:: ../Images/a4.jpg
..
..
.. Admonitions
.. .. note:: .. important:: .. tip:: .. warning::
.. Color: (blue) (orange) (green) (red)
..
.. Definition:
.. some text becomes strong (only one line)
.. description has to indented
.. -*- coding: utf-8 -*- with BOM.
.. include:: Includes.txt
.. _concept:
Concept
=======
SIPs
----
The following is a technical background information. Not needed to just use QFQ.
The SIPs (=Server Id Pairs) are uniq timestamps, created/registered on the fly for a specific browser session (=user). Every SIP is
registered on the server (= stored in a browser session) and contains one or more key/value pairs. The key/value pairs never leave
the server. The SIPs will be used:
* to protect values not to be spoofed by anyone,
* to protect values not to be altered by anyone,
* to grant access, e.g.:
* load and save forms,
* upload files,
* download files,
* PHP AJAX pages.
SIPs becomes invalid, as soon as the current browser session is destroyed. The client (= user) can't manipulate the content
of SIPs - it's only possible to reuse already registered SIPs by the user, who already owns the session.
Access privileges
-----------------
The Typo3 FE Groups can be used to implement access privileges. Such groups are assigned to
* Typo3 FE users,
* Typo3 pages,
* and/or Typo3 content records (e.g. QFQ records).
This will be used for general page structure privileges.
A `record base` privileges controlling (e.g. which user can edit
which person record) will be implicit configured, by the way that records are viewable / editable (or not) through
SQL in the specific QFQ tt-content statements.
Typo3 QFQ content element
-------------------------
Insert one or more QFQ content elements on a Typo3 page. Specify column and language per content record as wished.
The title of the QFQ content element will not be rendered on the frontend. It's only visible to the webmaster in the
backend for orientation.
.. _qfq_keywords:
QFQ Keywords (Bodytext)
^^^^^^^^^^^^^^^^^^^^^^^
**All of these parameters are optional.**
+-------------------+---------------------------------------------------------------------------------+
| Name | Explanation |
+===================+=================================================================================+
| form | | Formname. |
| | | Static: **form = person** |
| | | By SIP: **form = {{form:SE}}** |
| | | By SQL: **form = {{SELECT c.form FROM Config AS c WHERE c.id={{a:C}} }}** |
+-------------------+---------------------------------------------------------------------------------+
| r | | <record id>. The form will load the record with the specified id. |
| | | Static: **r = 123** |
| | | By SQL: **r = {{SELECT ...}}** |
| | | If not specified, the SIP parameter 'r' is used. |
+-------------------+---------------------------------------------------------------------------------+
| dbIndex | E.g. `dbIndex = {{indexQfq:Y}}` Select a DB index. Only necessary if a |
| | different than the standard DB should be used. |
+-------------------+---------------------------------------------------------------------------------+
| debugShowBodyText | If='1' and :ref:`configuration`:*showDebugInfo: yes*, shows a |
| | tooltip with bodytext |
+-------------------+---------------------------------------------------------------------------------+
| sqlLog | Overwrites :ref:`configuration`: :ref:`SQL_LOG` . Only affects `Report`, |
| | not `Form`. |
+-------------------+---------------------------------------------------------------------------------+
| sqlLogMode | Overwrites :ref:`configuration`: :ref:`SQL_LOG_MODE<SQL_LOG_MODE>` . |
| | Only affects `Report`, not `Form`. |
+-------------------+---------------------------------------------------------------------------------+
| render | See :ref:`report-render`. Overwrites :ref:`configuration`: render. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.fbeg | Start token for every field (=column) |
+-------------------+---------------------------------------------------------------------------------+
| <level>.fend | End token for every field (=column) |
+-------------------+---------------------------------------------------------------------------------+
| <level>.fsep | Separator token between fields (=columns) |
+-------------------+---------------------------------------------------------------------------------+
| <level>.fskipwrap | Skip wrapping (via fbeg, fsep, fend) of named columns. Comma separated list of |
| | column id's (starting at 1). See also the special column name '_noWrap' to |
| | suppress wrapping. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.shead | Static start token for whole <level>, independent if records are selected |
| | Shown before `head`. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.stail | Static end token for whole <level>, independent if records are selected. |
| | Shown after `tail`. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.head | Dynamic start token for whole <level>. Only if at least one record is select. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.tail | Dynamic end token for whole <level>. Only if at least one record is select. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.rbeg | Start token for row. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.rbgd | Alternating (per row) token. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.rend | End token for row. Will be rendered **before** subsequent levels are processed |
+-------------------+---------------------------------------------------------------------------------+
| <level>.renr | End token for row. Will be rendered **after** subsequent levels are processed |
+-------------------+---------------------------------------------------------------------------------+
| <level>.rsep | Seperator token between rows |
+-------------------+---------------------------------------------------------------------------------+
| <level>.sql | SQL Query |
+-------------------+---------------------------------------------------------------------------------+
| <level>.twig | Twig Template |
+-------------------+---------------------------------------------------------------------------------+
| <level>.althead | If <level>.sql has no rows selected (empty), these token will be rendered. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.altsql | If <level>.sql has no rows selected (empty) or affected (delete, update, insert)|
| | the <altsql> will be fired. Note: Sub queries of <level> are not fired, even if |
| | <altsql> selects some rows. |
+-------------------+---------------------------------------------------------------------------------+
| <level>.content | | *show* (default): content of current and sub level are directly shown. |
| | | *hide*: content of current and sub levels are stored and not shown. |
| | | *hideLevel*: content of current and sub levels are stored and only sub levels |
| | | are shown. |
| | | *store*: content of current and sub levels are stored and shown. |
| | | To retrieve the content: `{{<level>.line.content}}`. |
| | | See :ref:`syntax-of-report` |
+-------------------+---------------------------------------------------------------------------------+
.. _`report-render`:
Report: render
--------------
QFQ will render Report or Form in three situations:
#. Browser: The QFQ content is described by QFQ-Report syntax.
#. Browser: The QFQ content is described by a QFQ-Form.
#. API: The QFQ content is handled without Typo3. Typically a single tt-content record is specified in the request - only
that one is rendered by QFQ. This mode is typically used to export data like Excel Export.
Option 1 and 2 are distinguished by the parameter `form` (STORE_SIP or STORE_TYPO3). If 'form' is given, in most cases only a Form
should be shown (not the report).
+--------+-------------------------------------------------------------------------+
| render | Use |
+========+=========================================================================+
| single | Display Form or Report, but not both at the same time. If |
| | a SIP parameter 'form' is given, the form is rendered, else the report. |
+--------+-------------------------------------------------------------------------+
| both | Display Form and Report, both at the same time. |
+--------+-------------------------------------------------------------------------+
| api | Create output only when called via API (no Typo3). |
+--------+-------------------------------------------------------------------------+
Example::
render = both
form = {{form:SE}}
10 {
sql = SELECT ...
}
.. _`qfq-database`:
QFQ Database
------------
Recommended setup for Typo3 & QFQ Installation is with *two* databases. One for the Typo3 installation and one for QFQ.
A good practice is to name both databases equal, appending the suffix '_t3' and '_db'.
When QFQ is called, it checks for QFQ system tables. If they do not exist or have a lower version than the installed QFQ
version, the system tables will be automatically installed or updated.
.. _`system-tables`:
System tables
^^^^^^^^^^^^^
+---------------+------------+------------+
| Name | Use | Database |
+===============+============+============+
| Clipboard | Temporary | QFQ |
+---------------+------------+------------+
| Cron | Persistent | QFQ |
+---------------+------------+------------+
| Dirty | Temporary | QFQ | Data |
+---------------+------------+------------+
| Form | Persistent | QFQ |
+---------------+------------+------------+
| FormElement | Persistent | QFQ |
+---------------+------------+------------+
| FormSubmitLog | Persistent | QFQ | Data |
+---------------+------------+------------+
| MailLog | Persistent | QFQ | Data |
+---------------+------------+------------+
| Period | Persistent | Data |
+---------------+------------+------------+
| Split | Persistent | Data |
+---------------+------------+------------+
See :ref:`mail-log-page` and :ref:`form-submit-log-page` for some Frontend views for these tables.
* Check Bug #5459 / support of system tables in different DBs not supported.
.. _`multi-database`:
Multi Database
^^^^^^^^^^^^^^
Base: T3 & QFQ
""""""""""""""
QFQ typically interacts with one database, the QFQ database. The database used by Typo3 is typically a separate one.
Theoretically it might be the same (never tested), but it's strongly recommended to use a separated QFQ database to have
no problems on Typo3 updates and to have a clean separation between Typo3 and QFQ.
QFQ: System & Data
""""""""""""""""""
QFQ itself can be separated in 'QFQ system' (see :ref:`system-tables`) and 'QFQ data' databases (even more than one are
possible). The 'QFQ system' stores the forms, record locking, log tables and so on - `QFQ data` is for the rest.
A `Multi Database` setup is given, if 'QFQ system' is different from 'QFQ data'.
Data: Data1, Data2, ..., Data n
"""""""""""""""""""""""""""""""
Every database needs to be configured via :ref:`configuration` with it's own `index`.
`QFQ data` might switch between different 'data'-databases. In :ref:`configuration` one main `QFQ data` index will be specified
in `indexQfq`. If specific forms or reports should use a different database than that, `dbIndex` might change
`indexData` temporarily.
`dbIndex`: A `Report` (field `dbIndex`) as well as a `Form` (field `parameter`.`dbIndex`) can operate on a specific database.
A `Form` will:
* load the form-definition from `indexQfq` (table `Form` and `FormElement`),
* loads and save data from/in `indexData` (config.qfq.php) / `dbIndex` (form.parameter.dbIndex),
* retrieve extra information via `dbIndexExtra` - this is useful to offer information from a database and save them in a
different one.
The simplest setup, QFQ system & data in the same database, needs no `indexQfq / indexData` definition in
:ref:`configuration` or one or both of them set to '1'
To separate QFQ system and data, indexQfq and indexData will have different indexes.
A Multi Database setup might be useful for:
* several independent Typo3 QFQ installations (each have it's own form repository) and one central database, or
* one QFQ installation which should display / load /save records from different databases, or
* a combination of the above two.
Note:
* Option 'A' is the most simple and commonly used.
* Option 'B' separate the T3 and QFQ databases on two database hosts.
* Option 'C' is like 'B' but with a shared 'QFQ data'-database between three 'Typo3 / QFQ' instances.
* Further variants are possible.
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| | Domain | Website Host | T3 | QFQ system | QFQ data |
+===+================+==============+===============================+==============================+==================================+
| A | standalone.edu | 'w' | <dbHost>, <dbname>_t3, <dbnameSingle>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| B | appB1.edu | 'wApp' | <dbHostApp>, <dbnameB1>_t3 | <dbHostB1>, <dbnameApp>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| B | appB2.edu | 'wApp' | <dbHostApp>, <dbnameB2>_t3 | <dbHostB2>, <dbnameApp>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| C | appC1.edu | 'wAppC' | <dbHostAppC>, <dbnameC1>_t3 | <dbHostC>, <dbnameSysC1>_db | <dbHostData>_db, <dbNameData>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| C | appC2.edu | 'wAppC' | <dbHostAppC>, <dbnameC2>_t3 | <dbHostC>, <dbnameSysC2>_db | <dbHostData>_db, <dbNameData>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
| C | appC3.edu | 'wAppC3' | <dbHostAppC3>, <dbnameC3>_t3 | <dbHostC3>, <dbnameSysC3>_db | <dbHostData>_db, <dbNameData>_db |
+---+----------------+--------------+-------------------------------+------------------------------+----------------------------------+
In :ref:`config-qfq-php` mutliple database credentials can be prepared. Mandatory is at least one credential setup like
`DB_1_USER`, `DB_1_SERVER`, `DB_1_PASSWORD`, `DB_1_NAME`. The number '1' indicates the `dbIndex`. Increment the number
to specify further database credential setups.
Typically the credentials for `DB_1` also have access to the T3 database.
Different QFQ versions, shared database
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When using different QFQ versions and a shared 'QFQ data'-database, there is some risk of conflicting
'QFQ system' tables. Best is to always use the same QFQ version on all instances or use a Multi Database setup.
.. ==================================================
.. ==================================================
.. ==================================================
.. Header hierarchy
.. ==
.. --
.. ^^
.. ""
.. ;;
.. ,,
..
.. --------------------------------------------used to the update the records specified ------
.. Best Practice T3 reST: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/CheatSheet.html
.. Reference: https://docs.typo3.org/m/typo3/docs-how-to-document/master/en-us/WritingReST/Index.html
.. Italic *italic*
.. Bold **bold**
.. Code ``text``
.. External Links: `Bootstrap <http://getbootstrap.com/>`_
.. Add Images: .. image:: ../Images/a4.jpg
..
..
.. Admonitions
.. .. note:: .. important:: .. tip:: .. warning::
.. Color: (blue) (orange) (green) (red)
..
.. Definition:
.. some text becomes strong (only one line)
.. description has to indented
.. -*- coding: utf-8 -*- with BOM.
.. include:: Includes.txt
.. _debug:
Debug
=====
.. _QFQ_LOG:
QFQ Log
-------
Setup in :ref:`configuration`
* *qfqLog*
* Filename where to log QFQ debug and error messages.
* File is relative to the `<site path>` or absolute (starting with '/').
* Content: error situations of QFQ and debug, if enabled.
All non SQL related information will be logged to QFQ log file.
.. _SQL_LOG:
SQL Log
-------
Setup in :ref:`configuration`
* *sqlLog*
* Filename where to log SQL queries and statistical data.
* File is relative to the `<site path>` or absolute (starting with '/').
* Content: SQL queries and timestamp, formName/formId, fe_user, success, affected rows, newly created record
id's and accessed from IP.
* The global setting can be overwritten by defining `sqlLog` inside of a QFQ tt-content record.
.. _SQL_LOG_MODE:
* *sqlLogMode: all|modify|error|none*
* *all*: logs every SQL statement.
* *modify*: logs only statements who might potentially change data.
* *error*: logs only queries which generate SQL errors.
* *none*: no query logging at all.
* The global setting can be overwritten by defining `sqlLogMode` inside of a QFQ tt-content record.
* *showDebugInfo = [yes|no|auto],[download]*
If active, displays additional information in the Frontend (FE). This is typically helpful during development.
* *yes*:
* Form:
* For every internal link/button, show tooltips with decoded SIP on mouseover.
* Shows an 'Edit form'-button (wrench symbol) on a form. The link points to the T3 page with the :ref:`form-editor`.
* Report: Will be configured per tt-content record.
*debugShowBodyText = 1*
* *no*: No debug info.
* *auto*: Depending if there is a Typo3 BE session, set internally:
* *showDebugInfo = yes* (BE session exist)
* *showDebugInfo = no* (no BE session)
* *download*:
* During a download (especially by using wkhtml), temporary files are not deleted automatically. Also the
``wkhtmltopdf`` and ``pdfunite`` command lines will be logged to :ref:`QFQ_LOG`. Use this only to debug problems on download.
.. _MAIL_LOG:
MAIL Log
--------
Setup in :ref:`configuration`
* *mailLog*
* File which `sendEmail` logs sending mail.
* File is relative to the `<site path>` or absolute (starting with '/').
.. _`mail-log-page`:
Mail Log page (Table MailLog)
-----------------------------
For debugging purposes you may like to add a Mail Log page in the frontend.
The following QFQ code could be used for that purpose (put it in a QFQ PageContent element)::
# Page parameters
1.sql = SELECT @grId := '{{grId:C0:digit}}' AS _grId
2.sql = SELECT @summary := IF('{{summary:CE:alnumx}}' = 'true', 'true', 'false') AS _s
# Filters
10 {
sql = SELECT "'", gr.id, IF(gr.id = @grId, "' selected>", "'>"), gr.value, ' (Id: ', gr.id, ')'
FROM Ggroup AS gr
INNER JOIN MailLog AS ml ON ml.grId = gr.id
GROUP BY gr.id
head = <form onchange='this.submit();' class='form-inline'><input type='hidden' name='id' value='{{pageAlias:T0}}'>
Filter By Group: <select name='grId' class='form-control'><option value=''></option>
rbeg = <option value=
rend = </option>
tail = </select>
}
20 {
sql = SELECT IF(@summary = 'true', ' checked', '')
head = <div class='checkbox'><label><input type='checkbox' name='summary' value='true'
tail = >Summary</label></div></form>
}
# Mail Log
50 {
sql = SELECT id, '</td><td>', grId, '</td><td>', xId, '</td><td>'
, REPLACE(receiver, ',', '<br>'), '</td><td>', REPLACE(sender, ',', '<br>'), '</td><td>'
, DATE_FORMAT(modified, '%d.%m.%Y<br>%H:%i:%s'), '</td><td style="word-break:break-word;">'
, CONCAT('<b>', subject, '</b><br>', IF(@summary = 'true', CONCAT(SUBSTR(body, 1
, LEAST(IF(INSTR(body, '\n') = 0, 50, INSTR(body, '\n')), IF(INSTR(body, '<br>') = 0, 50
, INSTR(body, '<br>')))-1), ' ...'), CONCAT('<br>', REPLACE(body, '\n', '<br>'))) )
FROM MailLog
WHERE (grId = @grId OR @grId = 0)
ORDER BY modified DESC
LIMIT 100
head = <table class="table table-condensed table-hover"><tr>
<th>Id</th><th>grId</th><th>xId</th><th>To</th><th>From</th><th>Date</th><th>E-Mail</th></tr>
tail = </table>
rbeg = <tr><td>
rend = </td></tr>
}
.. _REDIRECT_ALL_MAIL_TO:
Redirect all mail to (catch all)
--------------------------------
Setup in :ref:`configuration`
* *redirectAllMailTo=john@doe.com*
* During the development, it might be helpful to configure a 'catch all' email address, which QFQ uses as the final receiver
instead of the original intended one.
* The setting will:
* Replace the 'To' with the configured one.
* Clear 'CC' and 'Bcc'
* Write a note and the original configured receiver at the top of the email body.
Show log files realtime
-----------------------
Display QFQ log files in realtime.
The following QFQ code could be used for that purpose (put it in a QFQ PageContent element)::
#
# {{logfile:SU}}
#
# Show buttons to select log file.
10 {
sql = SELECT '{{logfile:SU:::sql.log}}' AS '_=logfile'
head = <p>
tail = </p>
20.sql = SELECT CONCAT('p:{{pageAlias:T}}&logfile=sql.log|t:sql.log|b:', IF('{{logfile:R}}'='sql.log','primary','')) AS _page, ' '
, CONCAT('p:{{pageAlias:T}}&logfile=qfq.log|t:qfq.log|b:', IF('{{logfile:R}}'='qfq.log','primary','')) AS _page, ' '
, CONCAT('p:{{pageAlias:T}}&logfile=mail.log|t:mail.log|b:', IF('{{logfile:R}}'='mail.log','primary','')) AS _page
}
# Show selected log file.
100 {
sql = SELECT 'file:fileadmin/protected/log/{{logfile:R}}' AS _monitor
head = <pre id="monitor-1">Please wait</pre>
}
.. _`form-submit-log-page`:
Form Submit Log page
--------------------
For debugging purposes you may like to add a Form Submit Log page in the frontend.
The following QFQ code could be used for that purpose (put it in a QFQ PageContent element)::
# Filters
20.shead = <form onchange='this.submit()' class='form-inline'><input type='hidden' name='id' value='{{pageAlias:T0}}'>
20 {
sql = SELECT "'", id, IF(id = '{{formId:SC0}}', "' selected>", "'>"), name
FROM Form
ORDER BY name
head = <label for='formId'>Form:</label> <select name='formId' id='formId' class='form-control'><option value=0></option>
tail = </select>
rbeg = <option value=
rend = </option>
}