Skip to content
Snippets Groups Projects
Report.rst 195 KiB
Newer Older
                       "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>

Marc Egger's avatar
Marc Egger committed
.. _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.
Marc Egger's avatar
Marc Egger committed
  * The tt-content body is ignored in that case.
Marc Egger's avatar
Marc Egger committed
* 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

Marc Egger's avatar
Marc Egger committed
* 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.
Marc Egger's avatar
Marc Egger committed
  * 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.

Marc Egger's avatar
Marc Egger committed
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.

3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463
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 = ,&ensp;
  }

.. _`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>
    }