.. ================================================== .. ================================================== .. ================================================== .. 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 `_ .. Internal Link: :ref:`downloadButton` (default url text) or :ref:`download Button` (explicit url text) .. 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 .. _`report`: Report ====== QFQ Report Keywords ------------------- See :ref:`qfq_keywords`. QFQ content element ------------------- The QFQ extension is activated through tt-content records. One or more tt-content records per page are necessary to render *forms* and *reports*. Specify column and language per content record as wished. The title of the QFQ content element will not be rendered. It's only visible in the backend for orientation of the webmaster. To display a report on any given TYPO3 page, create a content element of type 'QFQ Element' (plugin) on that page. A simple example ^^^^^^^^^^^^^^^^ Assume that the database has a table person with columns firstName and lastName. To create a simple list of all persons, we can do the following:: 10.sql = SELECT firstName, lastName FROM Person The '10' indicates a *root level* of the report (see section :ref:`Structure`). The expression '10.sql' defines an SQL query for the specific level. When the query is executed, it will return a result having one single column name containing first and last name separated by a space character. The HTML output, displayed on the page, resulting from only this definition, could look as follows:: JohnDoeJaneMillerFrankStar I.e., QFQ will simply output the content of the SQL result row after row for each single level. Format output: mix style and content """""""""""""""""""""""""""""""""""" Variant 1: pure SQL ;;;;;;;;;;;;;;;;;;; To format the upper example, just create additional columns:: 10.sql = SELECT firstName, ", ", lastName, "
" FROM Person HTML output:: Doe, John
Miller, Jane
Star, Frank
Variant 2: SQL plus QFQ helper ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; QFQ provides several helper functions to wrap rows and columns, or to separate them. E.g. ``fsep`` stands for `field separate` and ``rend`` for `row end`:: 10.sql = SELECT firstName, lastName FROM Person 10.fsep = ', ' 10.rend =
HTML output:: Doe, John
Miller, Jane
Star, Frank
Check out all QFQ helpers under :ref:`qfq_keywords`. Due to mixing style and content, this becomes harder to maintain with more complex layout. Format output: separate style and content """"""""""""""""""""""""""""""""""""""""" The result of the query can be passed to the `Twig template engine `_ in order to fill a template with the data.:: 10.sql = SELECT firstName, lastName FROM Person 10.twig = {% for row in result %} {{ row.lastName }}, {{ row.firstName }
{% endfor %} HTML output:: Doe, John
Miller, Jane
Star, Frank
Check out :ref:`using-twig`. .. _`syntax-of-report`: Syntax of *report* ------------------ All **root level queries** will be fired in the order specified by 'level' (Integer value). For **each** row of a query (this means *all* queries), all subqueries will be fired once. * E.g. if the outer query selects 5 rows, and a nested query select 3 rows, than the total number of rows are 5 x 3 = 15 rows. There is a set of **variables** that will get replaced before ('count' also after) the SQL-Query gets executed: ``{{[:[:...]]}}`` Variables from specific stores. ``{{:R}}`` - use case of the above generic definition. See also :ref:`access-column-values`. ``{{.}}`` Similar to ``{{:R}}`` but more specific. There is no sanitize class, escape mode or default value. See :ref:`qfq_keywords` for a full list. See :ref:`variables` for a full list of all available variables. Different types of SQL queries are possible: SELECT, INSERT, UPDATE, DELETE, SHOW, REPLACE Only SELECT and SHOW queries will fire subqueries. Processing of the resulting rows and columns: * In general, all columns of all rows will be printed out sequentially. * On a per column base, printing of columns can be suppressed by starting the column name with an underscore '_'. E.g. ``SELECT id AS _id``. This might be useful to store values, which will be used later on in another query via the ``{{id:R}}`` or ``{{.columnName}}`` variable. To suppress printing of a column, use a underscore as column name prefix. E.g. ``SELECT id AS _id`` *Reserved column names* have a special meaning and will be processed in a special way. See :ref:`Processing of columns in the SQL result` for details. There are extensive ways to wrap columns and rows. See :ref:`wrapping-rows-and-columns` .. _`using-twig`: Using Twig ---------- How to write Twig templates is documented by the `Twig Project `_. QFQ passes the result of a given query to the corresponding Twig template using the Twig variable `result`. So templates need to use this variable to access the result of a query. Specifying a Template ^^^^^^^^^^^^^^^^^^^^^ By default the string passed to the **twig**-key is used as template directly, as shown in the simple example above:: 10.twig = {% for row in result %} {{ row.lastName }}, {{ row.firstName }
{% endfor %} However, if the string starts with **file:**, the template is read from the file specified.:: 10.twig = file:table_sortable.html.twig The file is searched relative to ** and if the file is not found there, it's searched relative to QFQ's *twig_template* folder where the included base templates are stored. The following templates are available: ``tables/default.html.twig`` A basic table with column headers, sorting and column filters using tablesorter and bootstrap. ``tables/single_vertical.html.twig`` A template to display the values of a single record in a vertical table. Links ^^^^^ The link syntax described in :ref:`column-link` is available inside Twig templates using the `qfqlink` filter:: {{ "u:http://www.example.com" | qfqlink }} will render a link to *http://www.example.com*. Json Decode ^^^^^^^^^^^ A String can be JSON decoded in Twig the following way:: {% set decoded = '["this is one", "this is two"]' | json_decode%} This can then be used as a normal object in Twig:: {{ decoded[0] }} will render *this is one*. Available Store Variables ^^^^^^^^^^^^^^^^^^^^^^^^^ QFQ also provides access to the following stores via the template context. * record * sip * typo3 * user * system * var All stores are accessed using their lower case name as attribute of the context variable `store`. The active Typo3 front-end user is therefore available as:: {{ store.typo3.feUser }} Example ^^^^^^^ The following block shows an example of a QFQ report. *10.sql* selects all users who have been assigned files in our file tracker. .. TODO use content = hide instead of _user once this is implemented *10.10* then selects all files belonging to this user, prints the username as header and then displays the files in a nice table with links to the files. :: 10.sql = SELECT assigned_to AS _user FROM FileTracker WHERE assigned_to IS NOT NULL GROUP BY _user ORDER BY _user 10.10.sql = SELECT id, path_scan FROM FileTracker WHERE assigned_to = '{{user:R}}' 10.10.twig =

{{ store.record.user }}

{% for row in result %} {% endfor %}
IDFile
{{ row.id }} {{ ("d:|M:pdf|s|t:"~ row.path_scan ~"|F:" ~ row.path_scan ) | qfqlink }}
Debug the bodytext ------------------ The parsed bodytext could be displayed by activating 'showDebugInfo' (:ref:`debug`) and specifying:: debugShowBodyText = 1 A small symbol with a tooltip will be shown, where the content record will be displayed on the webpage. Note: :ref:`debug` information will only be shown with *showDebugInfo: yes* in :ref:`configuration`. .. _`inline-report`: Inline Report editing --------------------- For quick changes it can be bothersome to go to the TYPO3 backend to update the page content and reload the page. For this reason, QFQ offers an inline report editing feature whenever there is a TYPO3 BE user logged in. A small link symbol will appear on the right-hand side of each report record. Please note that the TYPO3 Frontend cache is also deleted upon each inline report save. In order for the inline report editing to work, QFQ needs to be able to access the T3 database. This database is assumed to be accessible with the same credentials as specified with indexQfq. .. _`Structure`: Structure --------- A report can be divided into several levels. This can make report definitions more readable because it allows for splitting of otherwise excessively long SQL queries. For example, if your SQL query on the root level selects a number of person records from your person table, you can use the SQL query on the second level to look up the city where each person lives. See the example below:: 10.sql = SELECT id AS _pId, CONCAT(firstName, " ", lastName, " ") AS name FROM Person 10.rsep =
10.10.sql = SELECT CONCAT(postal_code, " ", city) FROM Address WHERE pId = {{10.pId}} 10.10.rbeg = ( 10.10.rend = ) This would result in:: John Doe (3004 Bern) Jane Miller (8008 Zürich) Frank Star (3012 Bern) Text across several lines ^^^^^^^^^^^^^^^^^^^^^^^^^ To get better human readable SQL queries, it's possible to split a line across several lines. Lines with keywords are on their own (:ref:`QFQ Keywords (Bodytext)` start a new line). If a line is not a 'keyword' line, it will be appended to the last keyword line. 'Keyword' lines are detected on: * . = * { * [.100 20.head =

20.tail =

Join mode: SQL """""""""""""" This is the default. All lines are joined with a *space* in between. E.g.:: 10.sql = SELECT 'hello world' FROM Mastertable Results to: ``10.sql = SELECT 'hello world' FROM Mastertable`` Notice the space between "...world'" and "FROM ...". Join mode: strip whitespace """"""""""""""""""""""""""" Ending a line with a \\ strips all leading and trailing whitespaces of that line joins the line directly (no extra space in between). E.g.:: 10.sql = SELECT 'hello world', 'd:final.pdf \ |p:id=export \ |t:Download' AS _pdf \ Results to: ``10.sql = SELECT 'hello world', 'd:final.pdf|p:id=export|t:Download' AS _pdf`` Note: the \\ does not force the joining, it only removes the whitespaces. To get the same result, the following is also possible:: 10.sql = SELECT 'hello world', CONCAT('d:final.pdf' '|p:id=export', '|t:Download') AS _pdf Nesting of levels ^^^^^^^^^^^^^^^^^ Levels can be nested. E.g.:: 10 { sql = SELECT ... 5 { sql = SELECT ... head = ... } } This is equal to:: 10.sql = SELECT ... 10.5.sql = SELECT ... 10.5.head = ... Leading / trailing spaces ^^^^^^^^^^^^^^^^^^^^^^^^^ By default, leading or trailing whitespaces are removed from strings behind '='. E.g. 'rend = test ' becomes 'test' for rend. To prevent any leading or trailing spaces, surround them by using single or double ticks. Example:: 10.sql = SELECT name FROM Person 10.rsep = ' ' 10.head = "Names: " Braces character for nesting ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ By default, curly braces '{}' are used for nesting. Alternatively angle braces '<>', round braces '()' or square braces '[]' are also possible. To define the braces to use, the **first line** of the bodytext has to be a comment line and the last character of that line must be one of '{[(<'. The corresponding braces are used for that QFQ record. E.g.:: # Specific code. > 10 < sql = SELECT head = > Per QFQ tt-content record, only one type of nesting braces can be used. Be careful to: * write nothing else than whitespaces/newline behind an **open brace** * the **closing brace** has to be alone on a line:: 10.sql = SELECT 'Yearly Report' 20 { sql = SELECT companyName FROM Company LIMIT 1 head =

tail =

} 30 { sql = SELECT depName FROM Department head =

tail =

5 { sql = SELECT 'detailed information for department' 1.sql = SELECT name FROM Person LIMIT 7 1.head = Employees: } } 30.5.tail = More will follow 50 { sql = SELECT 'A query with braces on their own' } .. _`access-column-values`: Access column values ^^^^^^^^^^^^^^^^^^^^ Columns of the upper / outer level result can be accessed via variables in two ways * STORE_RECORD: ``{{pId:R}}`` * Level Key: ``{{10.pId}}`` The STORE_RECORD will always be merged with previous content. The Level Keys are unique. .. important:: Multiple columns, with the same column name, can't be accessed individually. Only the last column is available. .. important:: Retrieving the *final* value of :ref:`special-column-names` is possible via '{{&:R}} (there is an '&' direct behind '{{') Example:: 10.sql = SELECT 'p:home&form=Person|s|b:success|t:Edit' AS _link 10.20.sql = SELECT '{{link:R}}', '{{&link:R}}' The first column of row `10.20` returns `p:home&form=Person|s|b:success|t:Edit`,the second column returns 'Edit'. Example STORE_RECORD:: 10.sql= SELECT p.id AS _pId, p.name FROM Person AS p 10.5.sql = SELECT adr.city, 'dummy' AS _pId FROM Address AS adr WHERE adr.pId={{pId:R}} 10.5.20.sql = SELECT '{{pId:R}}' 10.10.sql = SELECT '{{pId:R}}' The line '10.10' will output 'dummy' in cases where there is at least one corresponding address. If there are no addresses (all persons) it reports the person id. If there is at least one address, it reports 'dummy', cause that's the last stored content. Example 'level':: 10.sql= SELECT p.id AS _pId, p.name FROM Person AS p 10.5.sql = SELECT adr.city, 'dummy' AS _pId FROM Address AS adr WHERE adr.pId={{10.pId}} 10.5.20.sql = SELECT '{{10.pId}}' 10.10.sql = SELECT '{{10.pId}}' Notes to the level: +-------------+------------------------------------------------------------------------------------------------------------------------+ | Levels |A report is divided into levels. The Example has levels *10*, *20*, *30*, *30.5*, *30.5.1*, *50* | +-------------+------------------------------------------------------------------------------------------------------------------------+ | Qualifier |A level is divided into qualifiers *30.5.1* has 3 qualifiers *30*, *5*, *1* | +-------------+------------------------------------------------------------------------------------------------------------------------+ | Root levels |Is a level with one qualifier. E.g.: 10 | +-------------+------------------------------------------------------------------------------------------------------------------------+ | Sub levels |Is a level with more than one qualifier. E.g. levels *30.5* or *30.5.1* | +-------------+------------------------------------------------------------------------------------------------------------------------+ | Child |The level *30* has one child and child child: *30.5* and *30.5.1* | +-------------+------------------------------------------------------------------------------------------------------------------------+ | Example | *10*, *20*, *30*, *50** are root level and will be completely processed one after each other. | | | *30.5* will be executed as many times as *30* has row numbers. | | | *30.5.1* will be executed as many times as *30.5* has row numbers. | +-------------+------------------------------------------------------------------------------------------------------------------------+ Report Example 1:: # Displays current date 10.sql = SELECT CURDATE() # Show all students from the person table 20.sql = SELECT p.id AS pId, p.firstName, " - ", p.lastName FROM Person AS p WHERE p.typ LIKE "student" # Show all the marks from the current student ordered chronological 20.25.sql = SELECT e.mark FROM Exam AS e WHERE e.pId={{20.pId}} ORDER BY e.date # This query will never be fired, cause there is no direct parent called 20.30. 20.30.10.sql = SELECT 'never fired' .. _wrapping-rows-and-columns: Wrapping rows and columns: Level -------------------------------- Order and nesting of queries, will be defined with a TypoScript-alike syntax:: level.sublevel1.subsublevel2. ... * Each 'level' directive needs a final key, e.g: 20.30.10. **sql**. * A key **sql** is necessary in order to process a level. See all :ref:`QFQ Keywords (Bodytext)`. .. _`Processing of columns in the SQL result`: Processing of columns in the SQL result --------------------------------------- * The content of all columns of all rows will be printed sequentially, without separator (except one is defined). * Rows with :ref:`special-column-names` will be rendered internally by QFQ and the QFQ output of such processing (if there is any) is taken as the content. .. _special-column-names: Special column names -------------------- .. note:: Twig: respect that the 'special column name'-columns are rendered before Twig becomes active. The recommended way by using Twig is *not to use* special column names at all. Use the Twig version *qfqLink*. QFQ don't care about the content of any SQL-Query - it just copy the content to the output (=Browser). One exception are columns, whose name starts with '_'. E.g.:: 10.sql = SELECT 'All', 'cats' AS red, 'are' AS _green, 'grey in the night' AS _link * The first and second column are regular columns. No QFQ processing. * The third column (alias name 'green') is no QFQ special column name, but has an '_' at the beginning: this column content will be hidden. * The fourth column (alias name 'link') uses a QFQ special column name. Here, only in this example, it has no further meaning. * All columns in a row, with the same special column name (e.g. ``... AS _page``) will have the same column name: 'page'. To access individual columns a uniq column title is necessary and can be added ``...|column1``:: 10.sql = SELECT '..1..' AS '_page|column1', '..2..' AS '_page|column2' Those columns can be accessed via ``{{column1:R}}`` , ``{{column2:R}}`` (recommended) or ``{{10.column1}}`` , ``{{10.column2}}``. * To skip wrapping via ``fbeg``, ``fsep``, ``fend`` for dedicated columns, add the keyword ``|_noWrap`` to the column alias. Example:: 10.sql = SELECT 'world' AS 'title|_noWrap' Summary: .. note:: * For 'special column names': the column name together with the value controls how QFQ processes the column. * Special column names always start with '_'. * Important: to reference a column, the name has to be given without '_'. E.g. ``SELECT 'cat' AS _pet`` will be used with ``{{pet:R}}`` (notice the missing '_'). * Columns starting with a '_' but not defined as as QFQ special column name are hidden(!) - in other words: they are not **printed** as output. * Tip: if a column name starts with '_' the column name becomes '_....' - which will be hidden! To be safe: always define an alias! * Access to 'hidden' columns via ``{{.}}`` or ``{{:R}}`` are possible and often used. +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Reserved column name | Purpose | +========================+=============================================================================================================================================================================================+ | _link | :ref:`column-link` - Build links with different features. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _pageX or _PageX | :ref:`column_pageX` - Shortcut version of the link interface for fast creation of internal links. The column name is composed of the string *page*/*Page* | | | and a optional character to specify the type of the link. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _download | :ref:`download` - single file (any type) or concatenate multiple files (PDF, ZIP) | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _pdf, _file, _zip | :ref:`column_pdf` - Shortcut version of the link interface for fast creation of :ref:`download` links. Used to offer single file download or to concatenate several | | _Pdf, _File, _Zip | PDFs and printout of websites to one PDF file. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _savePdf | :ref:`column-save-pdf` - pre render PDF files | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _excel | :ref:`excel-export` - creates Excel exports based on QFQ Report queries, optional with pre uploaded Excel template files | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _yank | :ref:`copyToClipboard`. Shortcut version of the link interface | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _mailto | :ref:`column_mailto` - Build email links. A click on the link will open the default mailer. The address is encrypted via JS against email bots. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _sendmail | :ref:`column_sendmail` - Send emails. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _exec | :ref:`column_exec` - Run batch files or executables on the webserver. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _script | :ref:`column_script` - Run php function defined in an external script. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _vertical | :ref:`column_vertical` - Render Text vertically. This is useful for tables with limited column width. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _img | :ref:`column_img` - Display images. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _bullet |Display a blue/gray/green/pink/red/yellow bullet. If none color specified, show nothing. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _check |Display a blue/gray/green/pink/red/yellow checked sign. If none color specified, show nothing. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _nl2br |All newline characters will be converted to `
`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _striptags |HTML Tags will be stripped. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _htmlentities |Characters will be encoded to their HTML entity representation. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _fileSize |Show file size of a given file | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _mimeType |Show mime type of a given file | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _thumbnail | :ref:`thumbnail` - Create thumbnails on the fly. See :ref:`column-thumbnail`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _monitor | :ref:`column-monitor` - Constantly display a file. See :ref:`column-monitor`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _XLS |Used for Excel export. Append a `newline` character at the end of the string. Token must be part of string. See :ref:`excel-export`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _XLSs |Used for Excel export. Prepend the token 's=' and append a `newline` character at the string. See :ref:`excel-export`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _XLSb |Used for Excel export. Like '_XLSs' but encode the string base64. See :ref:`excel-export`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _XLSn |Used for Excel export. Prepend 'n=' and append a `newline` character around the string. See :ref:`excel-export`. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _noWrap |Skip wrapping via ``fbeg``, ``fsep``, ``fend``. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _hide |Hide a column with a special column name (like ``... AS _link``). Note: regular columns should be hidden by using '_' as the first letter of the column name. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _+|The content will be wrapped with ''. Example: ``SELECT 'example' AS '_+a href="http://example.com"'`` creates ``'example'`` | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | _= |The content will be saved in store 'user' under 'varname'. Retrieve it later via ``{{varname:U}}``. Example: ``'SELECT "Hello world" AS _=text'``. | | |See :ref:`STORE_USER`, :ref:`store_user_examples` | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |_ |Suppress output. Column names with leading underscore are used to select data from the database and make it available in other parts of the report without generating any output. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |_formJson |System internal. Return form with given id as json string. (`SELECT 'fid:[\|reduce][\|b64]' AS _formJson`). | | |Flag `reduce` filters out 'modified', 'created' as well as keys which hold default values. | | |Flag `b64` encodes the json string in base 64. | +------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ .. _column-link: Column: _link ^^^^^^^^^^^^^ * Most URLs will be rendered via class link. * Column names like ``_pagee`, ``_mailto``, ... are wrapper to class link. * The parameters for link contains a prefix to make them position-independent. * Parameter have to be separated with '|'. If '|' is part of the value, it needs to be escaped '\\|'. This can be done via QFQ SQL function ``QBAR()`` - see :ref:`qbar-escape-qfq-delimiter`. +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |URL|IMG|Meaning |Qualifier |Example |Description | +===+===+==============+===================================+===========================+========================================================================================================================================+ |x | |URL |u: |u:http://www.example.com |If an image is specified, it will be rendered inside the link, default link class: external | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |x | |Mail |m: |m:info@example.com |Default link class: email | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |x | |Page |p: |p:impressum |Prepend '?' or '?id=', no hostname qualifier (automatically set by browser) | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |x | |Download |d:[] |d:complete.pdf |Link points to `.../typo3conf/ext/qfq/Api/download.php`. Additional parameter SIP encoded. 'Download' needs SIP. See :ref:`download`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |x | |Copy to |y:[some content] |y:this will be copied |Click on it copies the value of 'y:' to the clipboard. Optional a file ('F:...') might be specified as source. | | | |clipboard | | |See :ref:`copyToClipboard`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Dropdown menu |z |z||p:home|t:Home |Creates a dropdown menu. See :ref:`dropdownMenu`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |websocket |w:ws://:/ | w:ws://localhost:123/demo |Send message given in 't:...' to websocket. See :ref:`websocket`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Text |t: |t:Firstname Lastname | | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Render |r: |r:3 |See: :ref:`render-mode`, Default: 0 | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Button | b[:0|1|] | b:0, b:1, b:success |'b', 'b:1': a bootstrap button is created. 'b:0' disable the button. : default, primary, success, info, warning,danger | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Picture |P: |P:bullet-red.gif |Picture '....'. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Edit |E |E |Show 'edit' icon as image | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |New |N |N |Show 'new' icon as image | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Delete |D |D |Show 'delete' icon as image (only the icon, no database record 'delete' functionality) | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Help |H |H |Show 'help' icon as image | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Info |I |I |Show 'information' icon as image | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Show |S |S |Show 'show' icon as image | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Glyph |G: |G:glyphicon-envelope |Show . Check: https://getbootstrap.com/docs/3.4/components/ | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Bullet |B:[] |B:green |Show bullet with ''. Colors: blue, gray, green, pink, red, yellow. Default Color: green. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Check |C:[] |C:green |Show checked with ''. Colors: blue, gray, green, pink, red, yellow. Default Color: green. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | |x |Thumbnail |T: |T:fileadmin/file.pdf |Creates a thumbnail on the fly. Size is specified via 'W'. See :ref:`column-thumbnail` | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Dimension |W:[width]x[height] |W:50x , W:x60 , W:50x60 |Defines the pixel size of thumbnail. See :ref:`column-thumbnail` | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |URL Params |U:=[&=]|U:a=value1&b=value2&c=... |Any number of additional Params. Links to forms: U:form=Person&r=1234. Used to create 'record delete'-links. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Tooltip |o: |o:More information here |Tooltip text | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Alttext |a: |a:Name of person |a) Alttext for images, b) Message text for :ref:`download` popup window. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Class |c:[n|] |c:text-muted |CSS class for link. n:no class attribute, : explicit named | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Attribute |A:=" |A:data-reference="person" |Custom attributes and a corresponding value. Might be used by application tests. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Target |g: |g:_blank |target=_blank,_self,_parent,. Default: no target | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Question |q: |q:please confirm |See: :ref:`question`. Link will be executed only if user clicks ok/cancel, default: 'Please confirm' | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Encryption |e:0|1|... |e:1 |Encryption of the e-mail: 0: no encryption, 1:via Javascript (default) | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Right |R |R |Defines picture position: Default is 'left' (no definition) of the 'text'. 'R' means 'right' of the 'text' | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |SIP |s[:0|1] |s, s:0, s:1 |If 's' or 's:1' a SIP entry is generated with all non Typo 3 Parameters. The URL contains only parameter 's' and Typo 3 parameter | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Mode |M:file|pdf|zip |M:file, M:pdf, M:zip |Mode. Used to specify type of download. One or more element sources needs to be configured. See :ref:`download`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |File |F: |F:fileadmin/file.pdf |Element source for download mode file|pdf|zip. See :ref:`download`. | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | | |Delete record | x[:a|r|c] |x, x:r, x:c |a: ajax (only QFQ internal used), r: report (default), c: close (current page, open last page) | +---+---+--------------+-----------------------------------+---------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ .. _render-mode: Render mode ^^^^^^^^^^^ The following table might be hard to read - but it's really useful to understand. It solves a lot of different situations. If there are no special condition (like missing value, or suppressed links), render mode 0 is sufficient. But if the URL text is missing, or the URL is missing, OR the link should be rendered in sql row 1-10, but not 5, then render mode might dynamically control the rendered link. * Column *Mode* is the render mode and controls how the link is rendered. +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |Mode |Given: url & text |Given: only url | Given: only text |Description | +============+=====================+====================+==================+===========================================================================+ |0 (default) |text |url | |text or image will be shown, only if there is a url, page or mailto | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |1 |text |url |text |text or image will be shown, independently of whether there is a url or not| +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |2 |text | | |no link if text is empty | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |3 |text |url |text |no link, only text or image, incl. Optional tooltip. For Bootstrap buttons | | | | | | r:3 will set the button to disable and no link/sip is rendered. | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |4 |url |url |text |no link, show text, if text is empty, show url, incl. optional tooltip | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |5 | | | |nothing at all | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |6 | pure text | |pure text |no link, pure text | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |7 | pure url |pure url | |no link, pure url | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ |8 | pure sip |pure sip | |no link, no html, only the 13 digit sip code. | +------------+---------------------+--------------------+------------------+---------------------------------------------------------------------------+ Example:: 10.sql = SELECT CONCAT('u:', p.homepage, IF(p.showHomepage='yes', '|r:0', '|r:5') ) AS _link FROM Person AS p Tip: An easy way to switch between different options of rendering a link, incl. Bootstrap buttons, is to use the render mode. * no render mode or 'r:0' - the full functional link/button. * 'r:3' - the link/button is rendered with text/image/glyph/tooltip ... but without a HTML a-tag! For Bootstrap button, the button get the 'disabled' class. * 'r:5' - no link/button at all. Link Examples ^^^^^^^^^^^^^ +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ |SQL-Query | Result | +=======================================================================+=========================================================================================================================================+ | SELECT "m:info@example.com" AS _link | info@example.com as linked text, encrypted with javascript, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "m:info@example.com|c:0" AS _link | info@example.com as linked text, not encrypted, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "m:info@example.com|P:mail.gif" AS _link | info@example.com as linked image mail.gif, encrypted with javascript, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "m:info@example.com|P:mail.gif|o:Email" AS _link | *info@example.com* as linked image mail.gif, encrypted with javascript, class=external, tooltip: "sendmail" | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "m:info@example.com|t:mailto:info@example.com|o:Email" AS link | 'mail to *info@example.com*' as linked text, encrypted with javascript, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "u:www.example.com" AS _link | www.example as link, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "u:http://www.example.com" AS _link | *http://www.example* as link, class=external | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "u:www.example.com|q:Please confirm" AS _link | www.example as link, class=external, See: :ref:`question` | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "u:www.example.com|c:nicelink" AS _link | *http://www.example* as link, class=nicelink | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "p:form_person¬e=Text|t:Person" AS _link | Person | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "p:form_person|E" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "p:form_person|E|g:_blank" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "p:form_person|C" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "p:form_person|C:green" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "U:form=Person&r=123|x|D" as _link | "> | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "U:form=Person&r=123|x|t:Delete" as _link | Delete | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "s:1|d:full.pdf|M:pdf|p:id=det1&r=12|p:id=det2|F:cv.pdf| | Download | | t:Download|a:Create complete PDF - please wait" as _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "y:iatae3Ieem0jeet|t:Password|o:Clipboard|b" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ | SELECT "y|s:1|F:dir/data.R|t:Data|o:Clipboard|b" AS _link | | +-----------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------+ .. _question: Alert: Question ^^^^^^^^^^^^^^^ **Syntax** :: q[:[:[:[:[:[:]]]]]] * If a user clicks on a link, an alert is shown. If the user answers the alert by clicking on the 'positive button', the browser opens the specified link. If the user click on the negative answer (or waits for timout), the alert is closed and the browser does nothing. * All parameter are optional. * Parameter are separated by ':' * To use ':' inside the text, the colon has to be escaped by \\. E.g. 'ok\\ : I understand'. +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Parameter | Description | +======================+==========================================================================================================================+ | Text | The text shown by the alert. HTML is allowed to format the text. Any ':' needs to be escaped. Default: 'Please confirm'. | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Level | success, info, warning, danger | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Positive button text | Default: 'Ok' | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Negative button text | Default: 'Cancel'. To hide the second button: '-' | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Timeout in seconds | 0: no timeout, >0: after the specified time in seconds, the alert will dissapear and behaves like 'negative answer' | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ | Flag modal | 0: Alert behaves not modal. 1: (default) Alert behaves modal. | +----------------------+--------------------------------------------------------------------------------------------------------------------------+ Examples: +------------------------------------------------------------+---------------------------------------------------------------------------+ | SQL-Query | Result | +============================================================+===========================================================================+ | SELECT "p:form_person|q:Edit Person:warn" AS _link | Shows alert with level 'warn' | +------------------------------------------------------------+---------------------------------------------------------------------------+ | SELECT "p:form_person|q:Edit Person::I do:No way" AS _link | Instead of 'Ok' and 'Cancel', the button text will be 'I do' and 'No way' | +------------------------------------------------------------+---------------------------------------------------------------------------+ | SELECT "p:form_person|q:Edit Person:::10" AS _link | The Alert will be shown 10 seconds | +------------------------------------------------------------+---------------------------------------------------------------------------+ | SELECT "p:form_person|q:Edit Person:::10:0" AS _link | The Alert will be shown 10 seconds and is not modal. | +------------------------------------------------------------+---------------------------------------------------------------------------+ .. _column_pageX: Columns: _page[X] ^^^^^^^^^^^^^^^^^ The colum name is composed of the string *page* and a trailing character to specify the type of the link. **Syntax**:: 10.sql = SELECT "[options]" AS _page[] with: [options] = [p:][|t:][|o:][|q:][|c:][|g:][|r:] = c,d,e,h,i,n,s +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ | column name | Purpose |default value of question parameter | Mandatory parameters | +===============+===============================================+=====================================+==============================================+ |_page |Internal link without a grafic |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pagec |Internal link without a grafic, with question |*Please confirm!* |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_paged |Internal link with delete icon (trash) |*Delete record ?* | | U:form=&r= *or* | | | | | | U:table=&r= | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pagee |Internal link with edit icon (pencil) |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pageh |Internal link with help icon (question mark) |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pagei |Internal link with information icon (i) |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pagen |Internal link with new icon (sheet) |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ |_pages |Internal link with show icon (magnifier) |empty |p:[¶m] | +---------------+-----------------------------------------------+-------------------------------------+----------------------------------------------+ * All parameter are optional. * Optional set of predefined icons. * Optional set of dialog boxes. +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | Parameter | Description | Default value |Example | +==============+=================================================================================================+==========================================================+===============================================================+ | |TYPO3 page id or page alias. |The current page: *{{pageId}}* |45 application application&N_param1=1045 | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |Text, wrapped by the link. If there is an icon, text will be displayed to the right of it. |empty string | | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |Text to appear as a ToolTip |empty string | | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |If there is a question text given, an alert will be opened. Only if the user clicks on 'ok', |**Expected "=" to follow "see"** | | | |the link will be called | | | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |CSS Class for the tag | | | | | | | | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |Parameter for HTML 'target='. F.e.: Opens a new window |empty |P | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |Show/render a link at all or not. See :ref:`render-mode` | | | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ | |s | |'s': create a SIP | +--------------+-------------------------------------------------------------------------------------------------+----------------------------------------------------------+---------------------------------------------------------------+ .. _column_paged: Column: _paged ^^^^^^^^^^^^^^ These column offers a link, with a confirmation question, to delete one record (mode 'table') or a bunch of records (mode 'form'). After deleting the record(s), the current page will be reloaded in the browser. **Syntax** :: 10.sql = SELECT "U:table=&r=|q:|..." AS _paged 10.sql = SELECT "U:form=&r=|q:|..." AS _paged .. If the record to delete contains column(s), whose column name match on `%pathFileName%` and such a column points to a real existing file, such a file will be deleted too. If the table contains records where the specific file is multiple times referenced, than the file is not deleted (it would break the still existing references). Multiple references are not found, if they use different colummnnames or tablenames. Mode: table """"""""""" * ``table=`` * ``r=`` Deletes the record with id '' from table '
'. Mode: form """""""""" * ``form=`` * ``r=`` Deletes the record with id '' from the table specified in form '' as primary table. Additional action *FormElement* of type *beforeDelete* or *afterDelete* will be fired too. Examples """""""" :: 10.sql = SELECT 'U:table=Person&r=123|q:Do you want delete John Doe?' AS _paged 10.sql = SELECT 'U:form=person-main&r=123|q:Do you want delete John Doe?' AS _paged .. _column_ppageX: Columns: _Page[X] ^^^^^^^^^^^^^^^^^ * Similar to ``_page[X]`` * Parameter are position dependent and therefore without a qualifier! :: "[[¶m=value&...]] | [text] | [tooltip] | [question parameter] | [class] | [target] | [render mode]" as _Pagee. .. _column_ppaged: Column: _Paged ^^^^^^^^^^^^^^ * Similar to ``_paged`` * Parameter are position dependent and therefore without a qualifier! :: "[table=
&r=[¶m=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged. "[form=&r=[¶m=value&...] | [text] | [tooltip] | [question parameter] | [class] | [render mode]" as _Paged. .. _column_vertical: Column: _vertical ^^^^^^^^^^^^^^^^^ Use instead :ref:`vertical-column-title` .. warning:: The '... AS _vertical' is deprecated - do not use it anymore. Render text vertically. This is useful for tables with limited column width. The vertical rendering is achieved via CSS tranformations (rotation) defined in the style attribute of the wrapping tag. You can optionally specify the rotation angle. **Syntax** :: 10.sql = SELECT "|[]" AS _vertical .. +-------------+--------------------------------------------------------------------------------------------------------+-----------------+ |**Parameter**| **Description** |**Default value**| +=============+========================================================================================================+=================+ | | The string that should be rendered vertically. |none | +-------------+--------------------------------------------------------------------------------------------------------+-----------------+ | | How many degrees should the text be rotated? The angle is measured clockwise from baseline of the text.|*270* | +-------------+--------------------------------------------------------------------------------------------------------+-----------------+ The text is surrounded by some HTML tags in an effort to make other elements position appropriately around it. This works best for angles close to 270 or 90. **Minimal Example** :: 10.sql = SELECT "Hello" AS _vertical 20.sql = SELECT "Hello|90" AS _vertical 20.sql = SELECT "Hello|-75" AS _vertical .. .. _column_mailto: Column: _mailto ^^^^^^^^^^^^^^^ Easily create Email links. **Syntax** :: 10.sql = SELECT "|[]" AS _mailto .. +--------------+----------------------------------------------------------------------------------------+-------------+ |**Parameter** |**Description** |**Default | | | |value** | +==============+========================================================================================+=============+ || The email address where the link should point to. |none | +--------------+----------------------------------------------------------------------------------------+-------------+ | | The text that should be displayed on the website and be linked to the email address. |none | | | This will typically be the name of the recipient. If this parameter is omitted, | | | | the email address will be displayed as link text. | | +--------------+----------------------------------------------------------------------------------------+-------------+ **Minimal Example** :: 10.sql = SELECT "john.doe@example.com" AS _mailto **Advanced Example** :: 10.sql = SELECT "john.doe@example.com|John Doe" AS _mailto .. _column_sendmail: Column: _sendmail ^^^^^^^^^^^^^^^^^ Format:: t:|f:|s:|b: [|c:[|B:[|r:] [|A:][|g:][|x:][|y:][|z:][|h:] [|e:][E:][|mode:html] [|C][d:][|F:][|u:][|p:] The following parameters can also be written as complete words for ease of use:: to:|from:|subject:|body: [|cc:[|bcc:[|reply-to:] [|autosubmit:][|grid:][|xid:][|xid2:][|xid3:][|header:] [|mode:html] Send emails. Every mail will be logged in the table `mailLog`. Attachments are supported. **Syntax** :: 10.sql = SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow" AS _sendmail 10.sql = SELECT "t:john@doe.com|f:jane@doe.com|s:Reminder tomorrow|b:Please dont miss the meeting tomorrow|A:off|g:1|x:2|y:3|z:4" AS _sendmail .. +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ |**Token** | **Parameter** |**Description** |**Required**| | short / long | | | | +==============+========================================+==================================================================================================+============+ | | f | email |**FROM**: Sender of the email. Optional: 'realname ' | yes | | | from | | | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | t | email[,email] |**TO**: Comma separated list of receiver email addresses. Optional: `realname ` | yes | | | to | | | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | c | email[,email] |**CC**: Comma separated list of receiver email addresses. Optional: 'realname ' | | | | cc | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | B | email[,email] |**BCC**: Comma separated list of receiver email addresses. Optional: 'realname ' | | | | bcc | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | r | REPLY-TO:email |**Reply-to**: Email address to reply to (if different from sender) | | | | reply-to | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | s | Subject |**Subject**: Subject of the email | yes | | | subject | | | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | b | Body |**Body**: Message - see also: :ref:`html-formatting` | yes | | | body | | | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | h | Mail header |**Custom mail header**: Separate multiple header with \\r\\n | | | | header | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | F | Attach file |**Attachment**: File to attach to the mail. Repeatable. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | u | Attach created PDF of a given URL |**Attachment**: Convert the given URL to a PDF and attach it the mail. Repeatable. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | p | Attach created PDF of a given T3 URL |**Attachment**: Convert the given URL to a PDF and attach it the mail. Repeatable. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | d | Filename of the attachment |**Attachment**: Useful for URL to PDF converted attachments. Repeatable. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | C | Concat multiple F|p|u| together |**Attachment**: All following (until the next 'C') 'F|p|u' concatenated to one attachment. | | | | | Repeatable. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | A | flagAutoSubmit 'on' / 'off' |If 'on' (default), add mail header 'Auto-Submitted: auto-send' - suppress OoO replies | | | | autosubmit | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | g | grId |Will be copied to the mailLog record. Helps to setup specific logfile queries | | | | grid | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | x | xId |Will be copied to the mailLog record. Helps to setup specific logfile queries | | | | xid | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | y | xId2 |Will be copied to the mailLog record. Helps to setup specific logfile queries | | | | xid2 | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | | z | xId3 |Will be copied to the mailLog record. Helps to setup specific logfile queries | | | | xid3 | | | yes | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | e | encode|decode|none |**Subject**: will be htmlspecialchar() encoded, decoded (default) or none (untouched) | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | E | encode|decode|none |**Body**: will be htmlspecialchar() encoded, decoded (default) or none (untouched). | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ | mode | html |**Body**: will be send as a HTML mail. | | +--------------+----------------------------------------+--------------------------------------------------------------------------------------------------+------------+ * **e|E**: By default, QFQ stores values 'htmlspecialchars()' encoded. If such values have to send by email, the html entities are unwanted. Therefore the default setting for 'subject' und 'body' is to decode the values via 'htmlspecialchars_decode()'. If this is not wished, it can be turned off by `e=none` and/or `E=none`. **Minimal Example** :: 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available." AS _sendmail This will send an email with subject *Latest News* from company@example.com to john.doe@example.com. **Advanced Examples** :: 10.sql = SELECT "t:customer1@example.com,Firstname Lastname , Firstname Lastname | \\ f:company@example.com|s:Latest News|b:The new version is now available.|r:sales@example.com|A:on|g:101|x:222|c:ceo@example.com|B:backup@example.com" AS _sendmail This will send an email with subject *Latest News* from company@example.com to customer1, customer2 and customer3 by using a realname for customer2 and customer3 and suppress generating of OoO answer if any receiver is on vacation. Additional the CEO as well as backup will receive the mail via CC and BCC. For debugging, please check :ref:`REDIRECT_ALL_MAIL_TO`. .. _html-formatting: **Mail Body HTML Formatting** In order to send an email with HTML formatting, such as bold text or bullet lists, specify 'mode=html'. The subsequent contents will be interpreted as HTML and is rendered correctly by most email programs. .. _attachment: Attachment """""""""" The following options are provided to attach files to an email: +-------+------------------------------------------------------+--------------------------------------------------------+ | Token | Example | Comment | +=======+======================================================+========================================================+ | F | F:fileadmin/file3.pdf | Single file to attach | +-------+------------------------------------------------------+--------------------------------------------------------+ | u | u:www.example.com/index.html?key=value&... | A URL, will be converted to a PDF and than attached. | +-------+------------------------------------------------------+--------------------------------------------------------+ | p | p:?id=export&r=123&_sip=1 | A SIP protected local T3 page. | | | | Will be converted to a PDF and than attached. | +-------+------------------------------------------------------+--------------------------------------------------------+ | d | d:myfile.pdf | Name of the attachment in the email. | +-------+------------------------------------------------------+--------------------------------------------------------+ | C | C|u:http://www.example.com|F:file1.pdf|C|F:file2.pdf | Concatenate all named sources to one PDF file. The | | | | souces has to be PDF files or a web page, which will be| | | | converted to a PDF first. | +-------+------------------------------------------------------+--------------------------------------------------------+ Any combination (incl. repeating them) are possible. Any source will be added as a single attachment. Optional any number of sources can be concatenated to a single PDF file: 'C|F:|F:|p:export&a=123'. Examples in Report:: # One file attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|F:fileadmin/summary.pdf" AS _sendmail # Two files attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|F:fileadmin/summary.pdf|F:fileadmin/detail.pdf" AS _sendmail # Two files and a webpage (converted to PDF) are attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|F:fileadmin/summary.pdf|F:fileadmin/detail.pdf|p:?id=export&r=123|d:person.pdf" AS _sendmail # Two webpages (converted to PDF) are attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|p:?id=export&r=123|d:person123.pdf|p:?id=export&r=234|d:person234.pdf" AS _sendmail # One file and two webpages (converted to PDF) are *concatenated* to one PDF and attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|C|F:fileadmin/summary.pdf|p:?id=export&r=123|p:?id=export&r=234|d:complete.pdf" AS _sendmail # One T3 webpage, protected by a SIP, are attached. 10.sql = SELECT "t:john.doe@example.com|f:company@example.com|s:Latest News|b:The new version is now available.|p:?id=export&r=123&_sip=1|d:person123.pdf" AS _sendmail .. _column_img: Column: _img ^^^^^^^^^^^^ Renders images. Allows to define an alternative text and a title attribute for the image. Alternative text and title text are optional. * If no alternative text is defined, an empty alt attribute is rendered in the img tag (since this attribute is mandatory in HTML). * If no title text is defined, the title attribute will not be rendered at all. **Syntax** :: 10.sql = SELECT "|[]|[]" AS _img +--------------+-------------------------------------------------------------------------------------------+-----------------------------+ |**Parameter** |**Description** | **Default value/behaviour** | +==============+===========================================================================================+=============================+ |<pathtoimage> |The path to the image file. | none | +--------------+-------------------------------------------------------------------------------------------+-----------------------------+ |<alttext> |Alternative text. Will be displayed if image can't be loaded (alt attribute of img tag). | empty string | +--------------+-------------------------------------------------------------------------------------------+-----------------------------+ |<titletext> |Text that will be set as image title in the title attribute of the img tag. | no title attribute rendered | +--------------+-------------------------------------------------------------------------------------------+-----------------------------+ **Minimal Example** :: 10.sql = SELECT "fileadmin/img/img.jpg" AS _img **Advanced Examples** :: 10.sql = SELECT "fileadmin/img/img.jpg|Aternative Text" AS _img # alt="Alternative Text, no title 20.sql = SELECT "fileadmin/img/img.jpg|Aternative Text|" AS _img # alt="Alternative Text, no title 30.sql = SELECT "fileadmin/img/img.jpg|Aternative Text|Title Text" AS _img # alt="Alternative Text, title="Title Text" 40.sql = SELECT "fileadmin/img/img.jpg|Alternative Text" AS _img # alt="Alternative Text", no title 50.sql = SELECT "fileadmin/img/img.jpg" AS _img # empty alt, no title 60.sql = SELECT "fileadmin/img/img.jpg|" AS _img # empty alt, no title 70.sql = SELECT "fileadmin/img/img.jpg||Title Text" AS _img # empty alt, title="Title Text" 80.sql = SELECT "fileadmin/img/img.jpg||" AS _img # empty alt, no title .. _column_exec: Column: _exec ^^^^^^^^^^^^^ Run any command on the web server. * The command is run via web server, so with the uid of the web server. * The current working directory is the current web instance (e.g. ``/var/www/html``) . * All text send to 'stdout' will be returned. * Text send to 'stderr' is not returned at all. * If 'stderr' should be shown, redirect the output:: SELECT 'touch /root 2>&1' AS _exec * If 'stdout' / 'stderr' should not be displayed, redirect the output:: SELECT 'touch /tmp >/dev/null' AS _exec SELECT 'touch /root 2>&1 >/dev/null' AS _exec * Multiple commands can be concatenated by `;`:: SELECT 'date; date' AS _exec * If the return code is not 0, the string '[<rc>] ', will be prepended. * If it is not wished to see the return code, just add ``true`` to fake rc of 0 (only the last rc will be reported):: SELECT 'touch /root; true' AS _exec **Syntax** :: <command> .. +-------------+---------------------------------------------------+-----------------+ |**Parameter**| **Description** |**Default value**| +=============+===================================================+=================+ |<command> | The command that should be executed on the server.|none | +-------------+---------------------------------------------------+-----------------+ **Minimal Examples** :: 10.sql = SELECT "ls -s" AS _exec 20.sql = SELECT "./batchfile.sh" AS _exec .. _column_script: Column: _script ^^^^^^^^^^^^^^^ Run a php function defined in an external script. * All **column parameters are passed** as an associative array to the function as the first argument. * The second argument (here called $qfq) is an object which acts as an **interface to QFQ functionality** (see below). * The **current working directory** inside the function is the current web instance (e.g. location of index.php). * Hint: Inside the script ``dirname(__FILE__)`` gives the path of the script. * All **output (e.g. using echo) will be rendered** by the special column as is. * If the function returns an associative array, then the **key-value pairs will be accessible via the VARS store `V`**. * If the function throws an **exception** then a standard QFQ error message is shown. * Text sent to 'stderr' by the php function is not returned at all. * The script has access to the following **qfq php functions** using the interface (see examples below): * $qfq::apiCall($method, $url, $data = '', $header = [], $timeout = 5) * arguments: * string $method: can be PUT/POST/GET/DELETE * string $url * string $data: a json string which will be added as GET parameters or as POST fields respectively. * array $header: is of the form ['Content-type: text/plain', 'Content-length: 100'] * int $timeout: is the number of seconds to wait until call is aborted. * return array: * [0]: Http status code * [1]: API answer as string. * $qfq::getVar($key, $useStores = 'FSRVD', $sanitizeClass = '', &$foundInStore = '', $typeMessageViolate = 'c') * arguments: * string $key: is the name of qfq variable * string $useStores: are the stores in which variable is searched (in order from left to right). see :ref:`store`. * string $sanitizeClass: (see :ref:`sanitize-class`) * string $foundInStore: is filled with the name of the store in which the variable was found. * string $typeMessageViolate: defines what to return if the sanitize class was violated: * 'c' : returns '!!<sanitize class>!!' * '0' : returns '0' * 'e' : returns '' * return string|false: * The value of the variable if found. * A placeholder if the variable violates the sanitize class. (see argument `$typeMessageViolate`) * `false` if the variable was not found. **Column Parameters** +-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+ | Token | Example | Comment | +===================+====================================================+====================================================================================+ | F | F:fileadmin/scripts/my_script.php | Path to the custom script relative to the current web instance | +-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+ | call | call:my_function | PHP function to call | +-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+ | arg | arg:a1=Hello&a2=World | Arguments are parsed and passed to the function together with the other parameters | +-------------------+----------------------------------------------------+------------------------------------------------------------------------------------+ **Example** * QFQ report :: 5.sql = SELECT "IAmInRecordStore" AS _savedInRecordStore 10.sql = SELECT "F:fileadmin/scripts/my_script.php|call:my_function|arg:a1=Hello&a2=World" AS _script 20.sql = SELECT "<br><br>Returened value: {{IAmInVarStore:V:alnumx}}" * PHP script (`fileadmin/scripts/my_script.php`) :: <?php function my_function($param, $qfq) { echo 'The first argument contains all attributes including "F" and "c":<br>'; print_r($param); echo '<br><br>get variable from record store:<br>'; print_r($qfq::getVar('savedInRecordStore', 'RE')); echo '<br><br>Make API call:<br>'; list($http_code, $answer) = $qfq::apiCall('GET', 'google.com'); echo 'Http code: ' . $http_code; // Returned array fills VARS store return ["IAmInVarStore" => "FooBar"]; } * Output :: The first argument contains all parameters including "F", "call" and "arg": Array ( [a1] => Hello [a2] => World [F] => fileadmin/scripts/my_script.php [call] => my_function [arg] => a1=Hello&a2=World ) get variable from record store: IAmInRecordStore Make API call: Http code: 301 Returened value: FooBar .. _column_pdf: Column: _pdf | _file | _zip ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Detailed explanation: :ref:`download` Most of the other Link-Class attributes can be used to customize the link. :: 10.sql = SELECT "[options]" AS _pdf, "[options]" AS _file, "[options]" AS _zip with: [options] = [d:<exportFilename][|p:<params>][|U:<params>][|u:<url>][|F:file[:path/file in zip]][|t:<text>][|a:<message>][|o:<tooltip>][|c:<class>][|r:<render mode>] * Parameter are position independent. * *<params>*: see :ref:`download-parameter-files` * For column ``_pdf`` and ``_zip``, the element sources ``p:...``, ``U:...``, ``u:...``, ``F:...`` might repeated multiple times. * For column ``_zip``, an optional parameter might define the path and filename inside the ZIP: `F:<orig filename>:<inside ZIP path and filename>` * To only render the page content without menus add the parameter ``type=2``. For example: ``U:id=pageToPrint&type=2&_sip=1&r=', r.id`` * Example:: # ... AS _file 10.sql = SELECT "F:fileadmin/test.pdf" as _pdf 20.sql = SELECT "p:id=export&r=1" as _pdf 30.sql = SELECT "t:Download PDF|F:fileadmin/test.pdf" as _pdf 40.sql = SELECT "t:Download PDF|p:id=export&r=1" as _pdf 50.sql = SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _pdf 60.sql = SELECT "d:complete.pdf|t:Download PDF|F:fileadmin/test.pdf|p:id=export&r=1|u:www.example.com" AS _pdf # ... AS _file 100.sql = SELECT "F:fileadmin/test.pdf" as _file 110.sql = SELECT "p:id=export&r=1" as _file 120.sql = SELECT "t:Download PDF|F:fileadmin/test.pdf" as _file 130.sql = SELECT "t:Download PDF|p:id=export&r=1" as _file # ... AS _zip 200.sql = SELECT "F:fileadmin/test.pdf" as _zip 210.sql = SELECT "p:id=export&r=1" as _zip 220.sql = SELECT "t:Download ZIP|F:fileadmin/test.pdf" as _zip 230.sql = SELECT "t:Download ZIP|p:id=export&r=1" as _zip # Several files 240.sql = SELECT "d:complete.zip|t:Download ZIP|F:fileadmin/test1.pdf|F:fileadmin/test2.pdf" as _zip # Several files with new path/filename 250.sql = SELECT "d:complete.zip|t:Download ZIP|F:fileadmin/test1.pdf:data/file-1.pdf|F:fileadmin/test2.pdf:data/file-2.pdf" as _zip .. _column-save-pdf: Column: _savePdf ^^^^^^^^^^^^^^^^ Generated PDFs can be stored directly on the server with this functionality. The link query consists of the following parameters: * One or more element sources (such as ``F:``, ``U:``, ``p:``, see :ref:`download-parameter-files`), including possible wkhtmltopdf parameters * The export filename and path as ``d:`` - for security reasons, this path has to start with *fileadmin/* and end with *.pdf*. Tips: * Please note that this option does not render anything in the front end, but is executed each time it is parsed. You may want to add a check to prevent multiple execution. * It is not advised to generate the filename with user input for security reasons. * If the target file already exists it will be overwriten. To save individual files, choose a new filename, for example by adding a timestamp. Example:: SELECT "d:fileadmin/result.pdf|F:fileadmin/_temp_/test.pdf" AS _savePdf SELECT "d:fileadmin/result.pdf|F:fileadmin/_temp_/test.pdf|U:id=test&--orientation=landscape" AS _savePdf .. _column-thumbnail: Column: _thumbnail ^^^^^^^^^^^^^^^^^^ For file ``T:<pathFileName>`` a thumbnail will be rendered, saved (to be reused) and a HTML ``<img>`` tag is returned, With the SIP encoded thumbnail. The thumbnail: * Size is specified via ``W:<dimension>``. The file is only rendered once and subsequent access is delivered via a local QFQ cache. * Will be rendered, if the source file is newer than the thumbnail or if the thumbnail dimension changes. * The caching is done by building the MD5 of pathFileName and thumbnail dimension. * Of multi page files like PDFs, the first page is used as the thumbnail. All file formats, which 'convert' ImageMagick (https://www.imagemagick.org/) supports, can be used. Office file formats are not supported. Due to speed and quality reasons, SVG files will be converted by inkscape. If a file format is not known, QFQ tries to show a corresponding file type image provided by Typo3 - such an image is not scaled. In :ref:`configuration` the exact location of ``convert`` and ``inkscape`` can be configured (optional) as well as the directory names for the cached thumbnails. +-------+--------------------------------+----------------------------------------------------------------------------+ | Token | Example | Comment | +=======+================================+============================================================================+ | T | T:fileadmin/file3.pdf | File render a thumbnail | +-------+--------------------------------+----------------------------------------------------------------------------+ | W | W:200x, W:x100, W:200x100 | Dimension of the thumbnail: '<width>x<height>. Both | | | | parameter are otional. If non is given the default is W:150x | +-------+--------------------------------+----------------------------------------------------------------------------+ | s | s:1, s:0 | Optional. Default: ``s:1``. If SIP is enabled, the rendered URL | | | | is a link via ``api/download.php?..``. Else a direct pathFileName. | +-------+--------------------------------+----------------------------------------------------------------------------+ | r | r:7 | Render Mode. Default 'r:0'. With 'r:7' only the url will be delivered. | +-------+--------------------------------+----------------------------------------------------------------------------+ The render mode '7' is useful, if the URL of the thumbnail have to be used in another way than the provided html-'<img>' tag. Something like ``<body style="background-image:url(bgimage.jpg)">`` could be solved with ``SELECT "<body style="background-image:url(", 'T:fileadmin/file3.pdf' AS _thumbnail, ')">'`` Example:: # SIP protected, IMG tag, thumbnail width 150px 10.sql = SELECT 'T:fileadmin/file3.pdf' AS _thumbnail # SIP protected, IMG tag, thumbnail width 50px 20.sql = SELECT 'T:fileadmin/file3.pdf|W:50' AS _thumbnail # No SIP protection, IMG tag, thumbnail width 150px 30.sql = SELECT 'T:fileadmin/file3.pdf|s:0' AS _thumbnail # SIP protected, only the URL to the image, thumbnail width 150px 40.sql = SELECT 'T:fileadmin/file3.pdf|s:1|r:7' AS _thumbnail Dimension """"""""" ImageMagick support various settings to force the thumbnail size. See https://www.imagemagick.org/script/command-line-processing.php#geometry or http://www.graphicsmagick.org/GraphicsMagick.html#details-geometry. Cleaning """""""" By default, the thumbnail directories are never cleaned. It's a good idea to install a cronjob which purges all files older than 1 year: :: find /path/to/files -type f -mtime +365 -delete Render """""" `Public` thumbnails are rendered at the time when the T3 QFQ record is executed. `Secure` thumbnails are rendered when the 'download.php?s=...' is called. The difference is, that the 'public' thumbnails blocks the page load until all thumbnails are rendered, instead the `secure` thumbnails are loaded asynchonous via the browser - the main page is already delivered to browser, all thumbnails appearing after a time. A way to *pre render* thumbnails, is a periodically called (hidden) T3 page, which iterates over all new uploaded files and triggers the rendering via column `_thumbnail`. Thumbnail: secure """"""""""""""""" Mode 'secure' is activated via enabling SIP (`s:1`, default). The thumbnail is saved under the path `thumbnailDirSecure` as configured in :ref:`configuration`. The secure path needs to be protected against direct file access by the webmaster / webserver configuration too. QFQ returns a HTML 'img'-tag: :: <img src="api/download.php?s=badcaffee1234"> Thumbnail: public """"""""""""""""" Mode 'public' has to be explicit activated by specifying `s:0`. The thumbnail is saved under the path `thumbnailDirPublic` as configured in :ref:`configuration`. QFQ returns a HTML 'img'-tag: :: <img src="{{thumbnailDirPublic:Y}}/<md5 hash>.png"> .. _column-monitor: Column: _monitor ^^^^^^^^^^^^^^^^ Detailed explanation: :ref:`monitor` **Syntax** :: 10.sql = SELECT 'file:<filename>|tail:<number of last lines>|append:<0 or 1>|interval:<time in ms>|htmlId:<id>' AS _monitor +-------------+-------------------------------------------------------------------------------------------+---------------------------+ |**Parameter**|**Description** |**Default value/behaviour**| +=============+===========================================================================================+===========================+ |<filename> |The path to the file. Relative to T3 installation directory or absolute. |none | +-------------+-------------------------------------------------------------------------------------------+---------------------------+ |<tail> |Number of last lines to show |30 | +-------------+-------------------------------------------------------------------------------------------+---------------------------+ |<append> |0: Retrieved content replaces current. 1: Retrieved content will be added to current. |0 | +-------------+-------------------------------------------------------------------------------------------+---------------------------+ |<htmlId> |Reference to HTML element to whose content replaced by the retrieve one. |monitor-1 | +-------------+-------------------------------------------------------------------------------------------+---------------------------+ .. _copyToClipboard: Copy to clipboard ^^^^^^^^^^^^^^^^^ +-------------------+--------------------------------+----------------------------------------------------------------------------+ | Token | Example | Comment | +===================+================================+============================================================================+ | y[:<content>] | y, y:some content | Initiates 'copy to clipboard' mode. Source might given text or page or url | +-------------------+--------------------------------+----------------------------------------------------------------------------+ | F:<pathFileName> | F:fileadmin/protected/data.R | pathFileName in DocumentRoot | +-------------------+--------------------------------+----------------------------------------------------------------------------+ Example:: 10.sql = SELECT 'y:hello world (yank)|t:content direct (yank)' AS _yank , 'y:hello world (link)|t:content direct (link)' AS _link , CONCAT('F:', p.pathFileName,'|t:File (yank)|o:', p.pathFileName) AS _yank , CONCAT('y|F:', p.pathFileName,'|t:File (link)|o:', p.pathFileName) AS _link FROM Person AS p .. _api_call_qfq_report: API Call QFQ Report (e.g. AJAX) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. note:: QFQ Report functionality protected by SIP offered to simple API calls: ``typo3conf/ext/qfq/Classes/Api/dataReport.php?s=....`` * General use API call to fire a specific QFQ tt-content record. Useful for e.g. AJAX calls. No Typo3 is involved. *No FE-Group access control*. * This defines just a simple API endpoint. For defining a rest API see: :ref:`restApi`. * Custom response headers can be defined by setting the variable `apiResponseHeader` in the record store. * Multiple headers should be separated by `\n` or `\r\n`. e.g.: `Content-Type: application/json\ncustom-header: fooBar` * If the api call succeeds the rendered content of the report is returned as is. (no additional formatting, no JSON encoding) * You can use MYSQL to create Json. See: `MYSQL create Json <https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html>`_ and `MariaDB Json functions <https://mariadb.com/kb/en/json-functions/>`_ * If a QFQ error occurs then a http-status of 400 is returned together with a JSON encoded response of the form: `{"status":"error", "message":"..."}` Example QFQ record JS (with tt_content.uid=12345):: 5.sql = SELECT "See console log for output" # Register SIP with given arguments. 10.sql = SELECT 'U:uid=12345&arg1=Hello&arg2=World|s|r:8' AS '_link|col1|_hide' # Build JS 10.tail = <script> console.log('start api request'); $.ajax({ url: 'typo3conf/ext/qfq/Classes/Api/dataReport.php?s={{&col1:RE}}', data: {arg3:456, arg4:567}, method: 'POST', dataType: 'TEXT', success: function(response, status, jqxhr) {console.log(response); console.log(jqxhr.getAllResponseHeaders());}, error: function(jqXHR, textStatus, errorThrown) {console.log(jqXHR.responseText, textStatus, errorThrown);} }); </script> Example QFQ record called by above AJAX:: # Create a dedicated tt-content record (on any T3 page, might be on the same page as the JS code). # The example above assumes that this record has the tt_content.uid=12345. render = api 10.sql = SELECT '{{arg1:S}} {{arg2:S}} {{arg3:C}} {{arg4:C}}', NOW() , 'Content-Type: application/json\ncustom-header: fooBar' AS _apiResponseHeader Example text returned by the above AJAX call:: Hello World 456 5672020-09-22 18:09:47 .. _rest_client: REST Client ^^^^^^^^^^^ .. note:: POST and GET data to external REST interfaces or other API services. Access to external services via HTTP / HTTPS is triggered via special column name *restClient*. The received data might be processed in subsequent calls. Example:: # Retrieve information. Received data is delivered in JSON and decoded / copied on the fly to CLIENT store (CLIENT store is emptied beforehand) 10.sql = SELECT 'n:https://www.dummy.ord/rest/person/id/123' AS _restClient 20.sql = SELECT 'Status: {{http-status:C}}<br>Name: {{name:C:alnumx}}<br>Surname: {{surname:C:alnumx}}' # Simple POST request via https. Result is printed on the page. 10.sql = SELECT 'n:https://www.dummy.ord/rest/person/id/123|method:POST|content:{"name":"John";"surname":"Doe"}' AS _restClient +-------------------+----------------------------------------------------+--------------------------------------------------------+ | Token | Example | Comment | +===================+================================+============================================================================+ | n | n:https://www.dummy.ord/rest/person | | +-------------------+----------------------------------------------------+--------------------------------------------------------+ | method | method:POST | GET, POST, PUT or DELETE | +-------------------+----------------------------------------------------+--------------------------------------------------------+ | content | content:{"name":"John";"surname":"Doe"} | Depending on the REST server JSON might be expected | +-------------------+----------------------------------------------------+--------------------------------------------------------+ | header | *see below* | | +-------------------+----------------------------------------------------+--------------------------------------------------------+ | timeout | timeout:5 | Default: 5 seconds. | +-------------------+----------------------------------------------------+--------------------------------------------------------+ **Header** * Each header must be separated by ``\r\n`` or `\n`. * An explicit given header will overwrite the named default header. * Default header: * *content-type: application/json* - if *content* starts with a ``{``. * *content-type: text/plain* - if *content* does not start with a ``{``. * *connection: close* - Necessary for HTTP 1.1. **Result received** * After a *REST client* call is fired, QFQ will wait up to *timeout* seconds for the answer. * By default, the whole received answer will be shown. To suppress the output: ``... AS '_restClient|_hide'`` * The variable ``{{http-status:C}}`` shows the `HTTP status code<https://en.wikipedia.org/wiki/List_of_HTTP_status_codes>`_. A value starting with '2..' shows success. * In case of an error, ``{{error-message:C:allbut}}`` shows some details. * In case the returned answer is a valid JSON string, it is flattened and automatically copied to STORE_CLIENT with corresponding key names. * NOTE: The CLIENT store is emptied beforehand! JSON answer example:: Answer from Server: { 'name' : 'John', 'address' : {'city' : 'Bern'} } Retrieve the values via: {{name:C:alnumx}}, {{city:C:alnumx}} .. _special-sql-functions: Special SQL Functions (prepared statements) ------------------------------------------- .. _qbar-escape-qfq-delimiter: QBAR: Escape QFQ Delimiter ^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QBAR(text) replaces "|" with "\\|" in `text` to prevent conflicts with the QFQ special column notation. In general this function should be used when there is a chance that unplanned '|'-characters occur. Example:: 10.sql = SELECT CONCAT('p:notes|t:Information: ', QBAR(Note.title), '|b') AS _link FROM Note In case 'Note.title' contains a '|' (like 'fruit | numbers'), it will confuse the '... AS _link' class. Therefore it's necessary to 'escape' (adding a '\' in front of the problematic character) the bar which is done by using ``QBAR()``. .. _qbar-escape-qfq-colon-coma: QCC: Escape colon / coma ^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QCC(text) replaces ":" with "\\:" and "," with "\\," in `text` to prevent conflicts with the QFQ notation. .. _qnl2br: QNL2BR: Convert newline to HTML '<br>' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QNL2BR(text) replaces `LF` or `CR/LF` by `<br>`. This can be used for data (containing LF) to output on a HTML page with correctly displayed linefeed. Example:: 10.sql = SELECT QNL2BR(Note.title) FROM Note One possibility how `LF` comes into the database is with form elements of type `textarea` if the user presses `enter` inside. .. _qmore-truncate-long-text: QMORE: Truncate Long Text - more/less ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QMORE(text, n) truncates `text` if it is longer than `n` characters and adds a "more.." button. If the "more..." button is clicked, the whole text is displayed. The stored procedure QMORE() will inject some HTML/CSS code. Example:: 10.sql = SELECT QMORE("This is a text which is longer than 10 characters", 10) Output:: This is a `more..` .. _qifempty: QIFEMPTY: if empty show token ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QIFEMPTY(input, token) returns 'token' if 'input' is 'empty string' / '0' / '0000-00-00' / '0000-00-00 00:00:00'. Example:: 10.sql = SELECT QIFEMPTY('hello world','+'), QIFEMPTY('','-') Output:: hello world- .. _qdate_format: QDATE_FORMAT: format a timestamp, show '-' if empty ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function QDATE_FORMAT(timestamp) returns 'dd.mm.YYYY hh:mm', if 'timestamp' is 0 returns '-' Example:: 10.sql = SELECT QDATE_FORMAT( '2019-12-31 23:55:41' ), ' / ', QDATE_FORMAT( 0 ), ' / ', QDATE_FORMAT( '' ) Output:: 31.12.2019 23:55 / - / - .. _qslugify: QSLUGIFY: clean a string ^^^^^^^^^^^^^^^^^^^^^^^^ Convert a string to only use alphanumerical characters and '-'. Characters with accent will be replaced without the accent. Non alphanumerical characters are stripped off. Spaces are replaced by '-'. All characters are lowercase. Example:: 10.sql = SELECT QSLUGIFY('abcd ABCD ae.ä.oe.ö.ue.ü z[]{}()<>.,?Z') Output:: abcd-abcd-ae-a-oe-o-ue-u-z-z .. _qent_squote: QENT_SQUOTE: convert single tick to HTML entity ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert all single ticks in a string to the HTML entity "'" Example:: 10.sql = SELECT QENT_SQUOTE("John's car") Output:: John's car .. _qent_dquote: QENT_DQUOTE: convert double tick to HTML entity " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Convert all double ticks in a string to the HTML entity """ Example:: 10.sql = SELECT QENT_SQUOTE('A "nice" event') Output:: A "nice" event .. _qesc_squote: QESC_SQUOTE: escape single tick ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Escape all single ticks with a backslash. Double escaped single ticks (two backslashes) will be replaced by a single escaped single tick. Example:: Be Music.style = "Rock'n' Roll" 10.sql = SELECT QESC_SQUOTE(style) FROM Music Output:: Rock\'n\'n Roll .. _qesc_dquote: QESC_SQUOTE: escape double tick ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Escape all double ticks with a backslash. Double escaped double ticks (two backslashes) will replaced by a single escaped double tick. Example:: Set Comment.note = 'A "nice" event' 10.sql = SELECT QESC_DQUOTE(style) FROM Music Output:: Rock\'n\'n Roll .. _strip_tags: strip_tags: strip html tags ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The SQL function strip_tags(input) returns 'input' without any HTML tags. Example:: 10.sql = SELECT strip_tags('<a href="https://example.com"><b>my name</b> <i>is john</i></a> - end of sentence') Output:: my name is john - end of sentence .. _qfq_function: QFQ Function ------------ QFQ SQL reports can be reused, similar to a function in a regular programming language, including call parameter and return values. * Per tt-content record the field 'subheader' (in Typo3 backend) defines the function name. The function can also referenced by using the tt-content number (`uid`) - but this is less readable. * The calling report calls the function by defining ``<level>.function = <function name>(var1, var2, ...) => return1, return2, ...`` * STORE_RECORD will be saved before calling the function and will be restored when the function has been finished. * The function has only access to STORE_RECORD variables which has been explicitly defined in the braces (var1, var2, ...). * The function return values will be copied to STORE_RECORD after the function finished. * Inside the QFQ function, all other STORES are fully available. * If ``<level>.function`` and ``<level>.sql`` are both given, ``<level>.function`` is processed first. * If ``<level>.function`` is given, but ``<level>.sql`` not, the values of ``shead, stail, althead`` are even processed. * If a function outputs something, this is *not* shown. * The output of a QFQ function is accessible via ``{{_output:R}}``. * It is possible to call functions inside of a function. * If ``render = api`` is defined in the function, both tt-content records can be saved on the *same* page and won't interfere. * FE Groups are not respected - don't use them on QFQ functions. Example tt-content record for the function:: Subheader: getFirstName Code: # # {{pId:R}} # render = api 100 { sql = SELECT p.firstName AS _firstName , NOW() AS now , CONCAT('p:{{pageAlias:T}}&form=person&r=', p.id ) AS '_pagee|_hide|myLink' FROM Person AS p WHERE p.id={{pId:R}} } Example tt-content record for the calling report:: # # Example how to use `<level>.function = ...` # 10 { sql = SELECT p.id AS _pId, p.name FROM Person AS p ORDER BY p.name head = <table class="table"><tr><th>Name</th><th>Firstname</th><th>Link (final)</th><th>Link (source)</th><th>NOW() (via Output)</th></tr> tail = </table> rbeg = <tr> renr = </tr> fbeg = <td> fend = </td> 20 { function = getFirstName(pId) => firstName, myLink } 30 { sql = SELECT '{{firstName:R}}', "{{myLink:R}}", "{{&myLink:R}}", '{{_output:R}}' fbeg = <td> fend = </td> } } Explanation: * Level 10 iterates over all `person`. * Level 10.20 calls QFQ function `getFirstName()` by delivering the `pId` via STORE_RECORD. The function expects the return value `firstName` and `myLink`. * The function selects in level 100 the person given by ``{{pId:R}}``. The `firstName` is not printed but a hidden column. Column ``now`` is printed. Column 'myLink' is a rendered link, but not printed. * Level 10.30 prints the return values ``firstName`` and ``myLink`` (as rendered link and as source definition). The last column is the output of the function - the value of ``NOW()`` .. tip:: If there are STORE_RECORD variables which can't be replaced: typically they have been not defined as function parameter or return values. .. _download: Download -------- +--------------------+--------------------------------------------------------+----------------------------------------+ | Mode | Security | Note | +====================+========================================================+========================================+ | Direct File access | | Files are public available. No access restriction | | Use ``<a href="...">`` | | | | Pro: Simple, links can be copied. | | Merge multiple sources: no | | | | Con: Directory access, guess of filenames, only | | but check :ref:`column-save-pdf` | | | | removing the file will deny access. | | Custom 'save as filename': no | +--------------------+--------------------------------------------------------+----------------------------------------+ | Persistent Link | | Access is be defined by a SQL statement. In *T3/BE | | Use ``..., 'd:1234|s:0' AS _link`` | | | | > Extension > QFQ > File > download* define a SQL | | Merge multiple sources: yes | | | | statement. | | Custom 'save as filename': yes | | | | Pro: speaking URL, link can be copied, access can | | | | | can be defined a SQL statement. | | | | | Con: **Key might be altered by user**, permission | | | | | can't be user logged in dependent. | | +--------------------+--------------------------------------------------------+----------------------------------------+ | Secure Link | | **Default**. SIP protected link. | | Use ``..., 'd|F:file.pdf' AS _link`` | | | | Pro: Parameter can't be altered, most easy definition| | Merge multiple sources: yes | | | | in QFQ, access might be logged in user dependent. | | Custom 'save as filename': yes | | | | Cons: Links are assigned to a browser session and | | | | | can't be copied | | +--------------------+--------------------------------------------------------+----------------------------------------+ The rest of this section applies only to `Persistent Link` and `Secure Link`. Download offers: * Single file - download a single file (any type), * PDF create - one or concatenate several files (uploaded) and/or web pages (=HTML to PDF) into one PDF output file, * ZIP archive - filled with several files ('uploaded' or 'HTML to PDF'-converted). * Excel - created from scratch or fill a template xlsx with database values. By using the ``_link`` column name: * the option ``d:...`` initiate creating the download link and optional specifies * in ``SIP`` mode: an export filename (), * in ``persistent link`` mode: path download script (optional) and key(s) to identify the record with the PathFilename information (see below). * the optional ``M:...`` (Mode) specifies the export type (file, pdf, zip, export), * the alttext ``a:...`` specifies a message in the download popup. By using ``_pdf``, ``_Pdf``, ``_file``, ``_File``, ``_zip``, ``_Zip``, ``_excel`` as column name, the options `d`, `M` and `s` will be set. All files will be read by PHP - therefore the directory might be protected against direct web access. This is the preferred option to offer secure downloads via QFQ. Check `secure-direct-file-access`_. .. _download-parameter-files: Parameter and (element) sources ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * mode `secure link` (s:1) - *download*: ``d[:<exportFilename>]`` * *exportFilename* = <filename for save as> - Name, offered in the 'File save as' browser dialog. Default: 'output.<ext>'. If there is no `exportFilename` defined, then the original filename is taken (if there is one, else: output...). The user typically expects meaningful and distinct file names for different download links. * mode `persistent link` (s:0) - *download*: `d:[<path/name>]<key1>[/<keyN>]` This setup is divided in part a) and b): Part a) - offering the download link. * The whole part a) is optional. The download itself will work without it. * (Optional) *path/name* = of the QFQ `download.php` script. By default``typo3conf/ext/qfq/Classes/Api/download.php``. Three further possibilities: ``dl.php`` or ``dl2.php`` or ``dl3.php`` (see below). * *key1* = give a uniq identifier to select the wished record. Part b) - process the download * In the QFQ extension config: File > Query for direct download mode: `download.php` or `dl.php` or `dl2.php` or `dl3.php` up to 4 different SQL statements can be given with the regular QFQ download link syntax (skip the visual elements like button, text, glyph icon, question,...):: SELECT CONCAT('d|F:', n.pathFileName) FROM Note AS n WHERE n.id=? All `?` in the SQL statement will be replaced by the specified parameter. If there are more `?` than parameter, the last parameter will be reused for all pending `?`. E.g. ``10.sql = SELECT 'd:1234|t:File.pdf' AS _link`` creates a link ``<a href="typo3conf/ext/qfq/Classes/Api/download.php/1234"><span class="btn btn-default">File.pdf</span></span>``. If the user clicks on the link, QFQ will extract the `1234` argument and via ``download.php`` the query (defined in the Typo QFQ extension config) will be prepared and fires ``SELECT CONCAT('d|F:', n.pathFileName, '|t:File.pdf') FROM Note AS n WHERE n.id=1234``. The download of the file, specified by ``n.pathFileName``, will start. If no record ist selected, a custom error will be shown. If the query selectes more than one record, a general error will be shown. If one of ``dl.php`` or ``dl2.php`` or ``dl3.php`` should be used, please initially create the symlink(s), e.g. in the application directory (same level as typo3conf) ``ln -s typo3conf/ext/qfq/Classes/Api/download.php dl.php`` (or dl2.ph, dl3.php). Speaking URL) Instead of using a numeric value reference key, also a text can be used. Always take care that exactly one record is selected. The key is transferred by URL therefore untrusted: The sanitize class :ref:`alnumx<sanitize-class>` is applied. Example:: Query: SELECT CONCAT('d|F:', n.pathFileName) FROM Person AS p WHERE p.name=? AND p.firstName=? AND p.publish='yes' Link: https://example.com/dl.php/doe/john * *popupMessage*: ``a:<text>`` - will be displayed in the popup window during download. If the creating/download is fast, the window might disappear quickly. * *mode*: ``M:<mode>`` * *mode* = <file | pdf | zip | excel> * If ``M:file``, the mime type is derived dynamically from the specified file. In this mode, only one element source is allowed per download link (no concatenation). * In case of multiple element sources, only `pdf`, `zip` and `excel` (template mode) is supported. * If ``M:zip`` is used together with `p:...`, `U:...` or `u:..`, those HTML pages will be converted to PDF. Those files get generic filenames inside the archive. * If not specified, the **default** 'Mode' depends on the number of specified element sources (=file or web page): * If only one `file` is specified, the default is `file`. * If there is a) a page defined or b) multiple elements, the default is `pdf`. * *element sources* - for ``M:pdf`` or ``M:zip``, all of the following element sources may be specified multiple times. Any combination and order of these options are allowed. * *file*: ``F:<pathFileName>`` - relative or absolute pathFileName offered for a) download (single), or to be concatenated in a PDF or ZIP. * *page*: ``p:id=<t3 page>&<key 1>=<value 1>&<key 2>=<value 2>&...&<key n>=<value n>``. * By default, the options given to wkhtml will *not* be encoded by a SIP! * To encode the parameter via SIP: Add '_sip=1' to the URL GET parameter. E.g. ``p:id=form&_sip=1&form=Person&r=1``. In that way, specific sources for the `download` might be SIP encrypted. * Any current HTML cookies will be forwarded to/via `wkhtml`. This includes the current FE Login as well as any QFQ session. Also the current User-Agent are faked via the `wkhtml` page request. * If there are trouble with accessing FE_GROUP protected content, please check :ref:`wkhtmltopdf<wkhtml>`. * *url*: ``u:<url>`` - any URL, pointing to an internal or external destination. * *uid*: ``uid:<function name>`` - the output is treated as HTML (will be converted to PDF) or EXCEL data. * The called tt-content record is identified by `function name`, specified in the subheader field. Optional the numeric id of the tt-content record (=uid) can be given. * Only the specified QFQ content record will be rendered, without any Typo3 layout elements (Menu, Body,...) * QFQ will retrieve the tt-content's bodytext from the Typo3 database, parse it, and render it as a PDF or Execl data. * Parameters can be passed: ``uid:<tt-content record id>[&arg1=value1][&arg2=value2][...]`` and will be available via STORE_SIP in the QFQ PageContent, or passed as wkhtmltopdf arguments, if applicable. * For more obviously structuring, put the additional tt-content record on the same Typo3 page (where the QFQ tt-content record is located which produces the link) and specify ``render = api`` (`report-render`_). * *source*: ``source:<function name>[&arg1=value1][&arg2=value2][&...]`` - (similar to a `uid`) the output is treated as further sources. Example result reported by *function name* might be: ``F:file.pdf1|uid:myData&arg=2|...`` * Use this functionality to define a *central managed download* function, which can be reused anywhere by just specify the *function name* and required arguments. * The called tt-content record is identified by `function name`, specified in the subheader field. Optional the numeric id of the tt-content record (=uid) can be given. * The output of the tt-content record will be treated as further source arguments. Nothing else than valid source references should be printed. Separate the references as usual by '|'. * The supplied arguments are available via STORE_SIP (this is different from `qfq_function`_). * Tip: For more obviously structuring, put the additional tt-content record on the same Typo3 page (where the QFQ tt-content record is located which produces the link) and specify ``render = api`` (`report-render`_). * *WKHTML Options* for `page`, `urlParam` or `url`: * The 'HTML to PDF' will be done via `wkhtmltopdf`. * All possible options, suitable for `wkhtmltopdf`, can be submitted in the `p:...`, `u:...` or `U:...` element source. Check `wkhtmltopdf.txt <https://wkhtmltopdf.org/usage/wkhtmltopdf.txt>`_ for possible options. Be aware that key/value tuple in the documentation is separated by a space, but to respect the QFQ key/value notation of URLs, the key/value tuple in `p:...`, `u:...` or `U:...` has to be separated by '='. Please see last example below. * If an option contains an '&' it must be escaped with double \\ . See example. Most of the other Link-Class attributes can be used to customize the link as well. Example `_link`: :: # single `file`. Specifying a popup message window text is not necessary, cause a file directly accessed is fast. SELECT "d:file.pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link # single `file`, with mode SELECT "d:file.pdf|M:pdf|s|t:Download|F:fileadmin/pdf/test.pdf" AS _link # three sources: two pages and one file SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link # three sources: two pages and one file SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1|F:fileadmin/pdf/test.pdf" AS _link # three sources: two pages and one file, parameter to wkhtml will be SIP encoded SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1&_sip=1|p:id=detail2&r=1&_sip=1|F:fileadmin/pdf/test.pdf" AS _link # three sources: two pages and one file, the second page will be in landscape and pagesize A3 SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail&r=1|p:id=detail2&r=1&--orientation=Landscape&--page-size=A3|F:fileadmin/pdf/test.pdf" AS _link # One source and a header file. Note: the parameter to the header URL is escaped with double backslash. SELECT "d:complete.pdf|s|t:Complete PDF|p:id=detail2&r=1&--orientation=Landscape&--header={{URL:R}}?indexp.php?id=head\\&L=1|F:fileadmin/pdf/test.pdf" AS _link # One indirect source reference SELECT "d:complete.pdf|s|t:Complete PDF|source:centralPdf&pId=1234" AS _link An additional tt-content record is defined with `sub header: centralPdf`. One or multiple attachments might be concatenated. 10.sql = SELECT '|F:', a.pathFileName FROM Attachments AS a WHERE a.pId={{pId:S}} .. Example `_pdf`, `_zip`: :: # File 1: p:id=1&--orientation=Landscape&--page-size=A3 # File 2: p:id=form # File 3: F:fileadmin/file.pdf SELECT 't:PDF|a:Creating a new PDF|p:id=1&--orientation=Landscape&--page-size=A3|p:id=form|F:fileadmin/file.pdf' AS _pdf # File 1: p:id=1 # File 2: u:http://www.example.com # File 3: F:fileadmin/file.pdf SELECT 't:PDF - 3 Files|a:Please be patient|p:id=1|u:http://www.example.com|F:fileadmin/file.pdf' AS _pdf # File 1: p:id=1 # File 2: p:id=form # File 3: F:fileadmin/file.pdf SELECT CONCAT('t:ZIP - 3 Pages|a:Please be patient|p:id=1|p:id=form|F:', p.pathFileName) AS _zip .. Use the `--print-media-type` as wkhtml option to access the page with media type 'printer'. Depending on the website configuration this switches off navigation and background images. Rendering PDF letters ^^^^^^^^^^^^^^^^^^^^^ `wkhtmltopdf`, with the header and footer options, can be used to render multi page PDF letters (repeating header, pagination) in combination with dynamic content. Such PDFs might look-alike official letters, together with logo and signature. Best practice: #. Create a clean (=no menu, no website layout) letter layout in a separated T3 branch: :: page = PAGE page.typeNum = 0 page.includeCSS { 10 = typo3conf/ext/qfq/Resources/Public/Css/qfq-letter.css } // Grant access to any logged in user or specific development IPs [usergroup = *] || [IP = 127.0.0.1,192.168.1.* ] page.10 < styles.content.get [else] page.10 = TEXT page.10.value = access forbidden [global] #. Create a T3 `body` page (e.g. page alias: 'letterbody') with some content. Example static HTML content: :: <div class="letter-receiver"> <p>Address</p> </div> <div class="letter-sender"> <p><b>firstName name</b><br> Phone +00 00 000 00 00<br> Fax +00 00 000 00 00<br> </p> </div> <div class="letter-date"> Zurich, 01.12.2017 </div> <div class="letter-body"> <h1>Subject</h1> <p>Dear Mrs...</p> <p>Lucas ipsum dolor sit amet organa solo skywalker darth c-3p0 anakin jabba mara greedo skywalker.</p> <div class="letter-no-break"> <p>Regards</p> <p>Company</p> <img class="letter-signature" src=""> <p>Firstname Name<br>Function</p> </div> </div> #. Create a T3 letter-`header` page (e.g. page alias: 'letterheader') , with only the header information: :: <header> <img src="fileadmin/logo.png" class="letter-logo"> <div class="letter-unit"> <p class="letter-title">Department</p> <p> Company name<br> Company department<br> Street<br> City </p> </div> </header> #. Create a) a link (Report) to the PDF letter or b) attach the PDF (on the fly rendered) to a mail. Both will call the `wkhtml` via the `download` mode and forwards the necessary parameter. Use in `report`:: sql = SELECT CONCAT('d:Letter.pdf|t:',p.firstName, ' ', p.name , '|p:id=letterbody&pId=', p.id, '&_sip=1' , '&--margin-top=50mm' , '&--header-html={{BASE_URL_PRINT:Y}}?id=letterheader' # IMPORTANT: set margin-bottom to make the footer visible! , '&--margin-bottom=20mm' , '&--footer-right="Seite: [page]/[toPage]"' , '&--footer-font-size=8&--footer-spacing=10') AS _pdf FROM Person AS p ORDER BY p.id Sendmail. Parameter: :: sendMailAttachment={{SELECT 'd:Letter.pdf|t:', p.firstName, ' ', p.name, '|p:id=letterbody&pId=', p.id, '&_sip=1&--margin-top=50mm&--margin-bottom=20mm&--header-html={{BASE_URL_PRINT:Y}}?id=letterheader&--footer-right="Seite: [page]/[toPage]"&--footer-font-size=8&--footer-spacing=10' FROM Person AS p WHERE p.id={{id:S}} }} Replace the static content elements from 2. and 3. by QFQ Content elements as needed:: 10.sql = SELECT '<div class="letter-receiver"><p>', p.name AS '_+br', p.street AS '_+br', p.city AS '_+br', '</p>' FROM Person AS p WHERE p.id={{pId:S}} Export area ^^^^^^^^^^^ This description might be interesting if a page can't be protected by SIP. To offer protected pages, e.g. directly referenced files (remember: this is not recommended) in download links, the regular FE_GROUPs can't be used, cause the download does not have the current user privileges (it's a separate process, started as the webserver user). Create a separated export tree in Typo3 Backend, which is IP access restricted. Only localhost or the FE_GROUP 'admin' is allowed to access: :: tmp.restrictedIPRange = 127.0.0.1,::1 [IP = {$tmp.restrictedIPRange} ][usergroup = admin] page.10 < styles.content.get [else] page.10 = TEXT page.10.value = Please access from localhost or log in as 'admin' user. [global] .. _excel-export: Excel export ^^^^^^^^^^^^ This chapter explains how to create Excel files on the fly. Hint: For just up/downloading of excel files (without modification), check the generic Form :ref:`input-upload` element and the report 'download' (`column_pdf`_) function. The Excel file is build in the moment when the user request it, by clicking on a download link. Mode building: * `New`: The export file will be completely build from scratch. * `Template`: The export file is based on an earlier uploaded xlsx file (template). The template itself is unchanged. Injecting data into the Excel file is done in the same way in both modes: a Typo3 page (rendered without any HTML header or tags) contains one or more Typo3 QFQ records. Those QFQ records will create plain ASCII output. If the export file has to be customized (colors, pictures, headlines, ...), the `Template` mode is the preferred option. It's much easier to do all customizations via Excel and creating a template than by coding in QFQ / Excel export notation. Setup """"" * Create a special column name `_excel` (or `_link`) in QFQ/Report. As a source, define a T3 PageContent, which has to deliver the dynamic content (also :ref:`excel-export-sample<excel-export-sample>`). :: SELECT CONCAT('d:final.xlsx|M:excel|s:1|t:Excel (new)|uid:<tt-content record id>') AS _link * Create a T3 PageContent which delivers the content. * It is recommended to use the ``uid:<tt-content record id>`` syntax for excel imports, because there should be no html code on the resulting content. QFQ will retrieve the PageContent's bodytext from the Typo3 database, parse it, and pass the result as the instructions for filling the excel file. * Parameters can be passed: ``uid:<tt-content record id>?param=<value1>¶m2=<value2>`` and will be accessible in the SIP Store (S) in the QFQ PageContent. * Use the regular QFQ Report syntax to create output. * The newline at the end of every line needs to be CHAR(10). To make it simpler, the special column name ``... AS _XLS`` (see _XLS, _XLSs, _XLSb, _XLSn) can be used. * One option per line. * Empty lines will be skipped. * Lines starting with '#' will be skipped (comments). Inline comment signs are NOT recognized as comment sign. * Separate <keyword> and <value> by '='. +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | Keyword | Example | Description | +=============+======================+===================================================================================================+ | 'worksheet' | worksheet=main | Select a worksheet in case the excel file has multiple of them. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'mode' | mode=insert | Values: insert,overwrite. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'position' | position=A1 | Default is 'A1'. Use the excel notation. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'newline' | newline | Start a new row. The column will be the one of the last 'position' statement. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'str', 's' | s=hello world | Set the given string on the given position. The current position will be shift one to the right. | | | | If the string contains newlines, option'b' (base64) should be used. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'b' | b=aGVsbG8gd29ybGQK | Same as 's', but the given string has to Base64 encoded and will be decoded before export. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'n' | n=123 | Set number on the given position. The current position will be shift one to the right. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ | 'f' | f==SUM(A5:C6) | Set a formula on the given position. The current position will be shift one to the right. | +-------------+----------------------+---------------------------------------------------------------------------------------------------+ Create a output like this: :: position=D11 s=Hello s=World s=First Line newline s=Second line n=123 This fills D11, E11, F11, D12 In Report Syntax:: # With ... AS _XLS (token explicit given) 10.sql = SELECT 'position=D10' AS _XLS , 's=Hello' AS _XLS , 's=World' AS _XLS , 's=First Line' AS _XLS , 'newline' AS _XLS , 's=Second line' AS _XLS , 'n=123' AS _XLS # With ... AS _XLSs (token generated internally) 20.sql = SELECT 'position=D20' AS _XLS , 'Hello' AS _XLSs , 'World' AS _XLSs , 'First Line' AS _XLSs , 'newline' AS _XLS , 'Second line' AS _XLSs , 'n=123' AS _XLS # With ... AS _XLSb (token generated internally and content is base64 encoded) 30.sql = SELECT 'position=D30' AS _XLS , '<some content with special characters like newline/carriage return>' AS _XLSb .. _`excel-export-sample`: Excel export samples (54 is a example <tt-content record id>):: # From scratch (both are the same, one with '_excel' the other with '_link') SELECT CONCAT('d:new.xlsx|t:Excel (new)|uid:54') AS _excel SELECT CONCAT('d:new.xlsx|t:Excel (new)|uid:54|M:excel|s:1') AS _link # Template SELECT CONCAT('d:final.xlsx|t:Excel (template)|F:fileadmin/template.xlsx|uid:54') AS _excel # With parameter (via SIP) - get the Parameter on page 'exceldata' with '{{arg1:S}}' and '{{arg2:S}}' SELECT CONCAT('d:final.xlsx|t:Excel (parameter)|uid:54&arg1=hello&arg2=world') AS _excel Best practice """"""""""""" To keep the link of the Excel export close to the Excel export definition, the option :ref:`report-render` can be used. On a **single** T3 page create **two** QFQ tt-content records: tt-content record 1: * Type: QFQ * Content:: render = single 10.sql = SELECT CONCAT('d:new.xlsx|t:Excel (new)|uid:54|M:excel|s:1') AS _link tt-content record 2 (uid=54): * Type: QFQ * Content:: render = api 10.sql = SELECT 'position=D10' AS _XLS , 's=Hello' AS _XLS , 's=World' AS _XLS , 's=First Line' AS _XLS , 'newline' AS _XLS , 's=Second line' AS _XLS , 'n=123' AS _XLS .. _dropdownMenu: Dropdown Menu ------------- Creates a menu with custom links. The same notation and options are used as with regular QFQ links. Format String:: <dropdown menu symbol options>||<menu entry 1>||<menu entry 2>||... Each menu entry is separated by two bars! A menu entry itself might contain multiple single bars. Example 1:: SELECT 'z||p:home|t:Home|o:Jump to home||p:person&form=person&r=123|t:Edit: John Doe|s' AS _link This defines a menu (three vertical buttons) - a click on it shows two menu entries: 'Home' and 'Edit: John Doe' Format the dropdown menu symbol: * *Glyph*: Via ``G:<glyphicon name>`` any glyphicon can be defined. To hide the default glyph, specify: `G:0`. * *Text*: Via ``t:Menu`` an additional text will be displayed for the menu symbol. * *Tooltip*: Via ``o:Detail menu`` a tooltip is defined. * *Render mode*: Via ``r:3`` the menu is disabled. No menu entries / links / sip are rendered. * *Button*: Via ``b`` the dropdown meny symbol will be rendered with a button. Also `b:<style>` might set the BS color. Format a menu entry: * *qfq link*: All options as with a regular QFQ link. * *header*: If a text starts with '===', it becomes a header in the dropdown menu. Multiple headers are possible. Headers can't be a link. An additional `r:1` is necessary. * *separator*: If a text is exactly '---', it becomes a separator line between two menu entries. An additional ``r:1`` is necessary. * *disabled menu entry*: If a text starts with '---' (like separator), the following text becomes a disable menu entry. An additional ``r:1`` is necessary. Example 2:: SELECT CONCAT('z|t:Menu|G:0|o:Please select an option', '||p:home|t:Home|o:Jump to home|G:glyphicon-home|b:0', '||r:1|t:---', '||p:person&form=person&r=123|t:Edit: John Doe|s|q:Really edit?|G:glyphicon-user|b:0', '||t:===Header|r:1', '||d|p:form&form=person&r=',p.id,'|s|t:Download Person|b:0', '||r:1|t:---Disabled entry') AS _link Line 1: The dropdown menu symbol definition, with a text 'Menu' ``t:Menu``, but without the three vertical bullets ``G:0`` and a tooltip for the menu ``o:Please select an option``. Line 2: First menu entry. Directs to T3 page 'home' ``p:home``. ``t:Home`` sets the menu entry text. ``G:glyphicon-home`` set's glyphicon symbol in the menu entry. ``b:0`` switches off the button, which has been implicit activated by the use of ``G:...``. Line 3: A separator line. Line 4: A SIP encoded edit record link, with a question dialog. Line 5: A header line. Line 6: A PDF download. Line 7: A disabled menu entry. .. _websocket: WebSocket --------- Sending messages via WebSocket and receiving the answer is done via: :: SELECT 'w:ws://<host>:<port>/<path>|t:<message>' AS _websocket Instead of ``... AS _websocket`` it's also possible to use ``... AS _link`` (same syntax). The answer from the socket (if there is something) is written to output and stored in STORE_RECORD by given column (in this case 'websocket' or 'link'). .. tip:: To suppress the direct output, add ``|_hide`` to the column name. Example:: SELECT 'w:ws://<host>:<port>/<path>|t:<message>' AS '_websocket|_hide' .. tip:: To define a uniq column name (easy access by column name via STORE_RECORD) add ``|myName`` (replace *myName*). Example:: SELECT 'w:ws://<host>:<port>/<path>|t:<message>' AS '_websocket|myName' .. tip:: Get the answer from STORE_RECORD by using ``{{&...``. Check `access-column-values`_. Example:: SELECT 'w:ws://<host>:<port>/<path>|t:<message>' AS '_websocket|myName' Results: '{{myName:R}}' >> 'w:ws://<host>:<port>/<path>|t:<message>' '{{&myName:R}}' >> '<received socket answer>' .. _drag_and_drop: Drag and drop ------------- Order elements ^^^^^^^^^^^^^^ Ordering of elements via `HTML5 drag and drop` is supported via QFQ. Any element to order should be represented by a database record with an order column. If the elements are unordered, they will be ordered after the first 'drag and drop' move of an element. Functionality divides into: * Display: the records will be displayed via QFQ/report. * Order records: updates of the order column are managed by a specific definition form. The form is not a regular form (e.g. there are no FormElements), instead it's only a container to held the SQL update query as well as providing access control via SIP. The form is automatically called via AJAX. Part 1: Display list """""""""""""""""""" Display the list of elements via a regular QFQ content record. All 'drag and drop' elements together have to be nested by a HTML element. Such HTML element: * With ``class="qfq-dnd-sort"``. * With a form name: ``{{'form=<form name>' AS _data-dnd-api}}`` (will be replaced by QFQ) * Only *direct* children of such element can be dragged. * Every children needs a unique identifier ``data-dnd-id="<unique>"``. Typically this is the corresponding record id. * The record needs a dedicated order column, which will be updated through API calls in time. A ``<div>`` example HTML output (HTML send to the browser): :: <div class="qfq-dnd-sort" data-dnd-api="typo3conf/ext/qfq/Classes/Api/dragAndDrop.php?s=badcaffee1234"> <div class="anyClass" id="<uniq1>" data-dnd-id="55"> Numbero Uno </div> <div class="anyClass" id="<uniq2>" data-dnd-id="18"> Numbero Deux </div> <div class="anyClass" id="<uniq3>" data-dnd-id="27"> Numbero Tre </div> </div> A typical QFQ report which generates those ``<div>`` HTML:: 10 { sql = SELECT '<div id="anytag-', n.id,'" data-dnd-id="', n.id,'">' , n.note, '</div>' FROM Note AS n WHERE grId=28 ORDER BY n.ord head = <div class="qfq-dnd-sort" {{'form=dndSortNote&grId=28' AS _data-dnd-api}}"> tail = </div> } A ``<table>`` based setup is also possible. Note the attribute ``data-columns="3"`` - this generates a dropzone which is the same column width as the outer table. :: <table> <tbody class="qfq-dnd-sort" data-dnd-api="typo3conf/ext/qfq/Classes/Api/dragAndDrop.php?s=badcaffee1234" data-columns="3"> <tr> class="anyClass" id="<uniq1>" data-dnd-id="55"> <td>Numbero Uno</td><td>Numbero Uno.2</td><td>Numbero Uno.3</td> </tr> <tr class="anyClass" id="<uniq2>" data-dnd-id="18"> <td>Numbero Deux</td><td>Numbero Deux.2</td><td>Numbero Deux.3</td> </tr> <tr class="anyClass" id="<uniq3>" data-dnd-id="27"> <td>Numbero Tre</td><td>Numbero Tre.2</td><td>Numbero Tre.3</td> </tr> </tbody> </table> A typical QFQ report which generates this HTML:: 10 { sql = SELECT '<tr id="anytag-', n.id,'" data-dnd-id="', n.id,'" data-columns="3">' , n.id AS '_+td', n.note AS '_+td', n.ord AS '_+td', '</tr>' FROM Note AS n WHERE grId=28 ORDER BY n.ord head = <table><tbody class="qfq-dnd-sort" {{'form=dndSortNote&grId=28' AS _data-dnd-api}} data-columns="3"> tail = </tbody><table> } Show / update order value in the browser ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; The 'drag and drop' action does not trigger a reload of the page. In case the order number is shown and the user does a 'drag and drop', the order number shows the old. To update the dragable elements with the latest order number, a predefined html id has to be assigned them. After an update, all changed order number (referenced by the html id) will be updated via AJAX. The html id per element is defined by `qfq-dnd-ord-id-<id>` where `<id>` is the record id. Same example as above, but with an updated `n.ord` column:: 10 { sql = SELECT '<tr id="anytag-', n.id,'" data-dnd-id="', n.id,'" data-columns="3">' , n.id AS '_+td', n.note AS '_+td', '<td id="qfq-dnd-ord-id-', n.id, '">', n.ord, '</td></tr>' FROM Note AS n WHERE grId=28 ORDER BY n.ord head = <table><tbody class="qfq-dnd-sort" {{'form=dndSortNote&grId=28' AS _data-dnd-api}} data-columns="3"> tail = </tbody><table> } Part 2: Order records """"""""""""""""""""" A dedicated `Form`, without any `FormElements`, is used to define the reorder logic (database update definition). Fields: * Name: <custom form name> - used in Part 1 in the ``_data-dnd-api`` variable. * Table: <table with the element records> - used to update the records specified by `dragAndDropOrderSql`. * Parameter: +-------------------------------------------------------+--------------------------------------------------------------+ | Attribute | Description | +=======================================================+==============================================================+ | orderInterval = <number> | Optional. By default '10'. Might be any number > 0. | +-------------------------------------------------------+--------------------------------------------------------------+ | orderColumn = <column name> | Optional. By default 'ord'. | +-------------------------------------------------------+--------------------------------------------------------------+ | dragAndDropOrderSql = | Query to selects the *same* records as the report in the | | {{!SELECT n.id AS id, n.ord AS ord FROM Note AS n | same *order!* Inconsistencies results in order differences. | | ORDER BY n.ord}} | The columns `id` and `ord` are *mandatory.* | +-------------------------------------------------------+--------------------------------------------------------------+ The form related to the example of part 1 ('div' or 'table'): :: Form.name: dndSortNote Form.table: Note Form.parameter: orderInterval = 1 Form.parameter: orderColumn = ord Form.parameter: dragAndDropOrderSql = {{!SELECT n.id AS id, n.ord AS ord FROM Note AS n WHERE n.grId={{grId:S0}} ORDER BY n.ord}} Re-Order: QFQ iterates over the result set of `dragAndDropOrderSql`. The value of column `id` have to correspond to the dragged HTML element (given by `data-dnd-id`). Reordering always start with `orderInterval` and is incremented by `orderInterval` with each record of the result set. The client reports a) the id of the dragged HTML element, b) the id of the hovered element and c) the dropped position of above or below the hovered element. This information is compared to the result set and changes are applied where appropriate. Take care that the query of part 1 (display list) does a) select the same records and b) in the same order as the query defined in part 2 (order records) via `dragAndDropOrderSql`. If you find that the reorder does not work at expected, those two sql queries are not identical. QFQ Icons --------- Located under ``typo3conf/ext/qfq/Resources/Public/icons``:: black_dot.png bullet-red.gif checked-red.gif emoji.svg mail.gif pointer.svg up.gif blue_dot.png bullet-yellow.gif checked-yellow.gif gear.svg marker.svg rectangle.svg upload.gif bulb.png checkboxinvert.gif construction.gif help.gif new.gif resize.svg wavy-underline.gif bullet-blue.gif checked-blue.gif copy.gif home.gif note.gif show.gif zoom.svg bullet-gray.gif checked-gray.gif delete.gif icons.svg pan.svg trash.svg bullet-green.gif checked-green.gif down.gif info.gif paste.gif turnLeft.svg bullet-pink.gif checked-pink.gif edit.gif loading.gif pencil.svg turnRight.svg QFQ CSS Classes --------------- * `qfq-table-50`, `qfq-table-80`, `qfq-table-100` - assigned to `<table>`, set min-width and column width to 'auto'. * Background Color: `qfq-color-grey-1`, `qfq-color-grey-2` - assigned to different tags (table, row, cell). * `qfq-100` - assigned to different tags, makes an element 'width: 100%'. * `qfq-left`- assigned to different tags, Text align left. * `qfq-sticky` - assigned to `<thead>`, makes the header sticky. * `qfq-badge`, `qfq-badge-error`, `qfq-badge-warning`, `qfq-badge-success`, `qfq-badge-info`, `qfq-badge-invers` - colorized BS3 badges. * `letter-no-break` - assigned to a `div` will protect a paragraph (CSS: page-break-before: avoid;) not to break around a page border (converted to PDF via wkhtml). Take care that `qfq-letter.css` is included in TypoScript setup. Bootstrap --------- * Table: `table` * Table > hover: `table-hover` * Table > condensed: `table-condensed` Example:: 10.sql = SELECT id, name, firstName, ... 10.head = <table class='table table-condensed qfq-table-50'> * `qfq-100`, `qfq-left` - makes e.g. a button full width and aligns the text left. Example:: 10.sql = SELECT "p:home&r=0|t:Home|c:qfq-100 qfq-left" AS _pages Tablesorter ----------- QFQ includes a third-party client-side table sorter: https://mottie.github.io/tablesorter/docs/index.html To turn any table into a sortable table: * Ensure that your QFQ installation imports the appropriate js/css files, see :ref:`setup-css-js`. * Add the `class="tablesorter"` to your `<table>` element. * Take care the `<table>` has a `<thead>` and `<tbody>` tag. * Every table with active tablesorter should have a uniq HTML id. .. important:: Custom settings will be saved per table automatically in the browser local storage. To distinguish different table settings, define an uniq HTML id per table. Example: `<table class="tablesorter" id="{{pageAlias:T}}-person">` - the `{{pageAlias:T}}` makes it easy to keep the overview over given name on the site. The *tablesorter* options: * Class `tablesorter-filter` enables row filtering. * Class `tablesorter-pager` adds table paging functionality. A page navigation is shown. * Class `tablesorter-column-selector` adds a column selector widget. * Activate/Save/Delete `views`: Insert inside of a table html-tag the command:: {{ '<uniqueName>' AS _tablesorter-view-saver }} This adds a menu to save the current view (column filters, selected columns, sort order). * `<uniqueName>` should be a name which is at least unique inside the typo3 content element. Example:: <table {{ 'allperson' AS _tablesorter-view-saver }} class="tablesorter tablesorter-filter tablesorter-column-selector" id="{{pageAlias:T}}-demo"> ... </table> * 'Views' can be saved as: * public: every user will see the `view` and can modify it. * private: only the user who created the `view` will see/modify it. * readonly: manually mark a `view` as readonly (no FE User can change it) by setting column `readonly='true'` in table `Setting` of the corresponding view (identified by `name`). * Views will be saved in the table 'Setting'. * Include 'font-awesome' CSS in your T3 page setup: `typo3conf/ext/qfq/Resources/Public/Css/font-awesome.min.css` to get the icons. * The view 'Clear' is always available and can't be modified. * To preselect a view, append a HTML anker to the current URL. Get the anker by selecting the view and copy it from the browser address bar. Example:: https://localhost/index.php?id=person#allperson=public:email * 'allperson' is the '<uniqueName>' of the `tablesorter-view-saver` command. * 'public' means the view is tagged as 'public' visible. * 'email' is the name of the view, as it is shown in the dropdown list. * If there is a public view with the name 'Default' and a user has no choosen a view earlier, that one will be selected. * You can export your tablesorter tables as CSV files using the output widget (be sure to include the separate JS file): * Create a button to trigger the export with the following Javascript:: $('table.tablesorter').trigger('outputTable'); * Default export file name: `tableExport.csv` * Exported with column separator `;` * Only currently filtered rows are exported. * Values are exported as text, without HTML tags * You can change the formatting/value of each cell as follows:: <td data-name="12345">CHF 12,345.-</td> * Headers and footers are exported as well. Customization of tablesorter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * See docs for more options: https://mottie.github.io/tablesorter/docs/index.html * Add the desired classes or data attributes to your table html, e.g.: * E.g. a dropdown: ``class="filter-select"`` (`example-widget-filter-custom <https://mottie.github.io/tablesorter/docs/example-widget-filter-custom.html>`_) +-----------------------------+----------------------------------------------------------------------------------------+ | Description | Syntax | +=============================+========================================================================================+ | Disable sorter | ``<th class="sorter-false">...`` | +-----------------------------+----------------------------------------------------------------------------------------+ | Disable filter | ``<th class="filter-false">...`` | +-----------------------------+----------------------------------------------------------------------------------------+ | Filter as dropdown | ``<th class="filter-select">...`` | +-----------------------------+----------------------------------------------------------------------------------------+ | Ignore entire row | Wrap ``<tr>`` inside a ``<tfoot>``. Caution: May cause undesired print behavior. | | | Use ``<tfoot style = "display:table-row-group;"> </tfoot>`` | +-----------------------------+----------------------------------------------------------------------------------------+ | Custom value for cell | ``<td data-text="...">...`` | +-----------------------------+----------------------------------------------------------------------------------------+ | Sorting for tables with | ``<tr class="tablesorter-hasChildRow">...</tr>`` | | child rows (e.g. drilldown) | ``<tr class="tablesorter-childRow">...</tr>`` | +-----------------------------+----------------------------------------------------------------------------------------+ * You can pass in a default configuration object for the main `tablesorter()` function by using the attribute `data-tablesorter-config` on the table. Use JSON syntax when passing in your own configuration, such as: :: data-tablesorter-config='{"theme":"bootstrap","widthFixed":true,"headerTemplate":"{content} {icon}","dateFormat":"ddmmyyyy","widgets":["uitheme","filter","saveSort","columnSelector","output"],"widgetOptions":{"filter_columnFilters":true,"filter_reset":".reset","filter_cssFilter":"form-control","columnSelector_mediaquery":false,"output_delivery":"download","output_saveFileName":"tableExport.csv","output_separator":";"} }' * If the above customization options are not enough, you can output your own HTML for the pager and/or column selector, as well as your own `$(document).ready()` function with the desired config. In this case, it is recommended not to use the above *tablesorter* classes since the QFQ javascript code could interfere with your javascript code. Example:: 10 { sql = SELECT id, CONCAT('form&form=person&r=', id) AS _Pagee, lastName, title FROM Person head = <table class="table tablesorter tablesorter-filter tablesorter-pager tablesorter-column-selector" id="{{pageAlias:T}}-ts1"> <thead><tr><th>Id</th><th class="filter-false sorter-false">Edit</th> <th>Name</th><th class="filter-select" data-placeholder="Select a title">Title</th> </tr></thead><tbody> tail = </tbody></table> rbeg = <tr> rend = </tr> fbeg = <td> fend = </td> } .. _monitor: Monitor ------- Display a (log)file from the server, inside the browser, which updates automatically by a user defined interval. Access to the file is SIP protected. Any file on the server is possible. * On a Typo3 page, define a HTML element with a unique html-id. E.g.:: 10.head = <pre id="monitor-1">Please wait</pre> * On the same Typo3 page, define an SQL column '_monitor' with the necessary parameter:: 10.sql = SELECT 'file:fileadmin/protected/log/sql.log|tail:50|append:1|refresh:1000|htmlId:monitor-1' AS _monitor * Short version with all defaults used to display system configured sql.log:: 10.sql = SELECT 'file:{{sqlLog:Y}}' AS _monitor, '<pre id="monitor-1" style="white-space: pre-wrap;">Please wait</pre>' .. _calendar_view: Calendar View ------------- QFQ is shipped with the JavaScript library https://fullcalendar.io/ (respect that QFQ uses V3) to provides various calendar views. Docs: https://fullcalendar.io/docs/v3 Include the JS & CSS files via Typoscript * typo3conf/ext/qfq/Resources/Public/Css/fullcalendar.min.css * typo3conf/ext/qfq/Resources/Public/JavaScript/moment.min.js * typo3conf/ext/qfq/Resources/Public/JavaScript/fullcalendar.min.js Integration: Create a `<div>` with * CSS class "qfq-calendar" * Tag `data-config`. The content is a Javascript object. Example:: 10.sql = SELECT 'Calendar, Standard' 10.tail = <div class="qfq-calendar" data-config='{ "themeSystem": "bootstrap3", "height": "auto", "defaultDate": "2020-01-13", "weekends": false, "defaultView": "agendaWeek", "minTime": "05:00:00", "maxTime": "20:00:00", "businessHours": { "dow": [ 1, 2, 3, 4 ], "startTime": "10:00", "endTime": "18:00" }, "events": [ { "id": "a", "title": "my event", "start": "2020-01-21"}, { "id": "b", "title": "my other event", "start": "2020-01-16T09:00:00", "end": "2020-01-16T11:30:00"} ]}'> </div> # "now" is in the past to switchoff 'highlight of today' 20.sql = SELECT 'Calendar, 3 day, custom color, agend&list' AS '_+h2' 20.tail = <div class="qfq-calendar" data-config='{ "themeSystem": "bootstrap3", "height": "auto", "header": { "left": "title", "center": "", "right": "agenda,listWeek" }, "defaultDate": "2020-01-14", "now": "1999-12-31", "allDaySlot": false, "weekends": false, "defaultView": "agenda", "dayCount": 3, "minTime": "08:00:00", "maxTime": "18:00:00", "businessHours": { "dow": [ 1, 2, 3, 4 ], "startTime": "10:00", "endTime": "18:00" }, "events": [ { "id": "a", "title": "my event", "start": "2020-01-15T10:15:00", "end": "2020-01-15T11:50:00", "color": "#25adf1", "textColor": "#000"}, { "id": "b", "title": "my other event", "start": "2020-01-16T09:00:00", "end": "2020-01-16T11:30:00", "color": "#5cb85c", "textColor": "#000"}, { "id": "c", "title": "Eventli", "start": "2020-01-15T13:10:00", "end": "2020-01-15T16:30:00", "color": "#fbb64f", "textColor": "#000"}, { "id": "d", "title": "Evento", "start": "2020-01-15T13:50:00", "end": "2020-01-15T15:00:00", "color": "#fb4f4f", "textColor": "#000"}, { "id": "d", "title": "Busy", "start": "2020-01-14T09:00:00", "end": "2020-01-14T12:00:00", "color": "#ccc", "textColor": "#000"}, { "id": "e", "title": "Banana", "start": "2020-01-16T13:30:00", "end": "2020-01-16T16:00:00", "color": "#fff45b", "textColor": "#000"} ]}'> </div> .. _reportAsFile: Report As File -------------- * If the toplevel token `file` is present inside the body of a QFQ tt-content element then the given report file is loaded and rendered. * The tt-content body is ignored in that case. * The path to the report file must be given relative to the report directory inside the qfq project directory. See :ref:`qfq-project-path-php` * QFQ provides some special system reports which are located inside the extension directory `typo3conf/ext/qfq/Resources/Private/Report` and can be directly rendered by prepending an underscore and omitting the file extension: * `file=_formEditor` will render the standard formEditor report * If the QFQ setting `reportAsFileAutoExport` (see :ref:`extension-manager-qfq-configuration`) is enabled, then every QFQ tt-content element which does not contain the `file` keyword is exported automatically when the report is rendered the first time. * The path of the created file is given by the typo3 page structure * The tt-content element body is replaced with `file=<path-to-new-file>` * **Backups** : Whenever a report file is edited via the frontend report editor then a backup of the previous version is saved in the `.backup` directory located in the same directory as the report file. Example tt-content body:: file=Home/myPage/qfq-report.qfqr # Everything else is ignored!! 10.sql = SELECT 'This is ignored!!' Example Home/myPage/qfq-report.qfqr:: # Some comment 10.sql = SELECT 'The file content is executed.' Example of rendered report:: The file content is executed. Report Examples --------------- The following section gives some examples of typical reports. Basic Queries ^^^^^^^^^^^^^ One simple query:: 10.sql = SELECT "Hello World" Result:: Hello World Two simple queries:: 10.sql = SELECT "Hello World" 20.sql = SELECT "Say hello" Result:: Hello WorldSay hello .. Two simple queries, with break:: 10.sql = SELECT "Hello World<br>" 20.sql = SELECT "Say hello" Result:: Hello World Say hello Accessing the database ^^^^^^^^^^^^^^^^^^^^^^ Real data, one single column:: 10.sql = SELECT p.firstName FROM ExpPerson AS p Result:: BillieElvisLouisDiana Real data, two columns:: 10.sql = SELECT p.firstName, p.lastName FROM ExpPerson AS p Result:: BillieHolidayElvisPresleyLouisArmstrongDianaRoss The result of the SQL query is an output, row by row and column by column, without adding any formatting information. See :ref:`Formatting Examples<Formatting Examples>` for examples of how the output can be formatted. .. _`Formatting Examples`: Formatting Examples ^^^^^^^^^^^^^^^^^^^ Formatting (i.e. wrapping of data with HTML tags etc.) can be achieved in two different ways: One can add formatting output directly into the SQL by either putting it in a separate column of the output or by using concat to concatenate data and formatting output in a single column. One can use 'level' keys to define formatting information that will be put before/after/between all rows/columns of the actual levels result. Two columns:: # Add the formatting information as a column 10.sql = SELECT p.firstName, " " , p.lastName, "<br>" FROM ExpPerson AS p Result:: Billie Holiday Elvis Presley Louis Armstrong Diana Ross One column 'rend' as linebreak - no extra column '<br>' needed:: 10.sql = SELECT p.firstName, " " , p.lastName, " ", p.country FROM ExpPerson AS p 10.rend = <br> Result:: Billie Holiday USA Elvis Presley USA Louis Armstrong USA Diana Ross USA Same with 'fsep' (column " " removed): 10.sql = SELECT p.firstName, p.lastName, p.country FROM ExpPerson AS p 10.rend = <br> 10.fsep = " " Result:: Billie Holiday USA Elvis Presley USA Louis Armstrong USA Diana Ross USA More HTML:: 10.sql = SELECT p.name FROM ExpPerson AS p 10.head = <ul> 10.tail = </ul> 10.rbeg = <li> 10.rend = </li> Result:: o Billie Holiday o Elvis Presley o Louis Armstrong o Diana Ross The same as above, but with braces:: 10 { sql = SELECT p.name FROM ExpPerson AS p head = <ul> tail = </ul> rbeg = <li> rend = </li> } Two queries:: 10.sql = SELECT p.name FROM ExpPerson AS p 10.rend = <br> 20.sql = SELECT a.street FROM ExpAddress AS a 20.rend = <br> Two queries: nested:: # outer query 10.sql = SELECT p.name FROM ExpPerson AS p 10.rend = <br> # inner query 10.10.sql = SELECT a.street FROM ExpAddress AS a 10.10.rend = <br> * For every record of '10', all records of 10.10 will be printed. Two queries: nested with variables:: # outer query 10.sql = SELECT p.id, p.name FROM ExpPerson AS p 10.rend = <br> # inner query 10.10.sql = SELECT a.street FROM ExpAddress AS a WHERE a.pId='{{10.id}}' 10.10.rend = <br> * For every record of '10', all assigned records of 10.10 will be printed. Two queries: nested with hidden variables in a table:: 10.sql = SELECT p.id AS _pId, p.name FROM ExpPerson AS p 10.rend = <br> # inner query 10.10.sql = SELECT a.street FROM ExpAddress AS a WHERE a.pId='{{10.pId}}' 10.10.rend = <br> Same as above, but written in the nested notation:: 10 { sql = SELECT p.id AS _pId, p.name FROM ExpPerson AS p rend = <br> 10 { # inner query sql = SELECT a.street FROM ExpAddress AS a WHERE a.pId='{{10.pId}}' rend = <br> } } Best practice *recommendation* for using parameter - see :ref:`access-column-values`:: 10 { sql = SELECT p.id AS _pId, p.name FROM ExpPerson AS p rend = <br> 10 { # inner query sql = SELECT a.street FROM ExpAddress AS a WHERE a.pId='{{pId:R}}' rend = <br> } } Create HTML tables. Each column is wrapped in ``<td>``, each row is wrapped in ``<tr>``:: 10 { sql = SELECT p.firstName, p.lastName, p.country FROM Person AS p head = <table class="table"> tail = </table> rbeg = <tr> rend = </tr> fbeg = <td> fend = </td> } Maybe a few columns belongs together and should be in one table column. Joining columns, variant A: firstName and lastName in one table column:: 10 { sql = SELECT CONCAT(p.firstName, ' ', p.lastName), p.country FROM Person AS p head = <table class="table"> tail = </table> rbeg = <tr> rend = </tr> fbeg = <td> fend = </td> } Joining columns, variant B: firstName and lastName in one table column:: 10 { sql = SELECT '<td>', p.firstName, ' ', p.lastName, '</td><td>', p.country, '</td>' FROM Person AS p head = <table class="table"> tail = </table> rbeg = <tr> rend = </tr> } Joining columns, variant C: firstName and lastName in one table column. Notice ``fbeg``, ``fend` and ``fskipwrap``:: 10 { sql = SELECT '<td>', p.firstName, ' ', p.lastName, '</td>', p.country FROM Person AS p head = <table class="table"> tail = </table> rbeg = <tr> rend = </tr> fbeg = <td> fend = </td> fskipwrap = 1,2,3,4,5 } Joining columns, variant D: firstName and lastName in one table column. Notice ``fbeg``, ``fend` and ``fskipwrap``:: 10 { sql = SELECT CONCAT('<td>', p.firstName, ' ', p.lastName, '</td>') AS '_noWrap', p.country FROM Person AS p head = <table class="table"> tail = </table> rbeg = <tr> rend = </tr> fbeg = <td> fend = </td> } Recent List ^^^^^^^^^^^ A nice feature is to show a list with last changed records. The following will show the 10 last modified (Form or FormElement) forms:: 10 { sql = SELECT CONCAT('p:{{pageAlias:T}}&form=form&r=', f.id, '|t:', f.name,'|o:', GREATEST(MAX(fe.modified), f.modified)) AS _page FROM Form AS f LEFT JOIN FormElement AS fe ON fe.formId = f.id GROUP BY f.id ORDER BY GREATEST(MAX(fe.modified), f.modified) DESC LIMIT 10 head = <h3>Recent Forms</h3> rsep = ,  } .. _`vertical-column-title`: Table: vertical column title ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To orientate a column title vertical, use the QFQ CSS classe `qfq-vertical` in td|th and `qfq-vertical-text` around the text. HTML example (second column title is vertical):: <table><thead> <tr> <th>horizontal</th> <th class="qfq-vertical"><span class="qfq-vertical-text">text vertical</span></th> </tr> </thead></table> QFQ example:: 10 { sql = SELECT title FROM Settings ORDER BY title fbeg = <th class="qfq-vertical"><span class="qfq-vertical-text"> fend = </span></th> head = <table><thead><tr> rend = </tr></thead> tail = </table> 20.sql = SELECT ... } .. _`store_user_examples`: STORE_USER examples ^^^^^^^^^^^^^^^^^^^ Keep variables per user session. Two pages (pass variable) """"""""""""""""""""""""" Sometimes it's useful to have variables per user (=browser session). Set a variable on page 'A' and retrieve the value on page 'B'. Page 'A' - set the variable:: 10.sql = SELECT 'hello' AS '_=greeting' Page 'B' - get the value:: 10.sql = SELECT '{{greeting:UE}}' If page 'A' has never been opened with the current browser session, nothing is printed (STORE_EMPTY gives an empty string). If page 'A' is called, page 'B' will print 'hello'. One page (collect variables) """""""""""""""""""""""""""" A page will be called with several SIP variables, but not at all at the same time. To still get all variables at any time:: # Normalize 10.sql = SELECT '{{order:USE:::sum}}' AS '_=order', '{{step:USE:::5}}' AS _step, '{{direction:USE:::ASC}}' AS _direction # Different links 20.sql = SELECT 'p:{{pageAlias:T}}&order=count|t:Order by count|b|s' AS _link, 'p:{{pageAlias:T}}&order=sum|t:Order by sum|b|s' AS _link, 'p:{{pageAlias:T}}&step=10|t:Step=10|b|s' AS _link, 'p:{{pageAlias:T}}&step=50|t:Step=50|b|s' AS _link, 'p:{{pageAlias:T}}&direction=ASC|t:Order by up|b|s' AS _link, 'p:{{pageAlias:T}}&direction=DESC|t:Order by down|b|s' AS _link 30.sql = SELECT * FROM Items ORDER BY {{order:U}} {{direction:U}} LIMIT {{step:U}} Simulate/switch user: feUser """""""""""""""""""""""""""" Just set the STORE_USER variable 'feUser'. All places with `{{feUser:T}}` has to be replaced by `{{feUser:UT}}`:: # Normalize 10.sql = SELECT '{{feUser:UT}}' AS '_=feUser' # Offer switching feUser 20.sql = SELECT 'p:{{pageAlias:T}}&feUser=account1|t:Become "account1"|b|s' AS _link, 'p:{{pageAlias:T}}&feUser={{feUser:T}}|t:Back to own identity|b|s' AS _link, Semester switch (remember last choice) """""""""""""""""""""""""""""""""""""" A current semester is defined via configuration in STORE_SYSTEM '{{semId:Y}}'. The first column in 10.sql `'{{semId:SUY}}' AS '_=semId'` saves the semester to STORE_USER via '_=semId'. The priority 'SUY' takes either the latest choose (STORE_SIP) or reuse the last used (STORE_USER) or (first time call during browser session) takes the default from config (STORE_SYSTEM):: # Semester switch 10 { sql = SELECT '{{semId:SUY}}' AS '_=semId' , CONCAT('p:{{pageAlias:T}}&semId=', sp.id, '|t:', QBAR(sp.name), '|s|b|G:glyphicon-chevron-left') AS _link , ' <button class="btn disabled ', IF({{semId:Y0}}=sc.id, 'btn-success', 'btn-default'), '">',sc.name, '</button> ' , CONCAT('p:{{pageAlias:T}}&semId=', sn.id, '|t:', QBAR(sn.name), '|s|b|G:glyphicon-chevron-right|R') AS _link FROM Semester AS sc LEFT JOIN semester AS sp ON sp.id=sc.id-1 LEFT JOIN semester AS sn ON sc.id+1=sn.id AND sn.show_semester_from<=CURDATE() WHERE sc.id={{semId:SUY}} ORDER BY sc.semester_von head = <div class="btn-group" style="position: absolute; top: 15px; right: 25px;"> tail = </div><p></p> }