Overview | |
Use this wiki plugin, introduced in Tiki3, to produce formatted reports from ADOdb SQL databases. The plugin content is parsed as a description of how to run and display a database query. If only an SQL statement (and parameters) is given, a default view of the returned data will be prepared. A report has a fairly restricted format, consisting of zero or more levels of grouping (supported by GROUP BY or ORDER BY clauses in the query's SQL) with a table generated per group. The table can have headers and footers, and links can be inserted which may take you to other web pages. Example: Copy to clipboard
|
Report Definition | |
A report definition is written in a simple "micro-language" that declares zero or more levels of grouping (supported by ORDER BY clauses in the query's SQL) and generates a table for each group. The tables may have headers and footers, and links can be generated for most visible elements will can take you to other web pages. If only the SQL (and parameters) are provided, a default view of the returned data will be prepared. The report generator language is designed to be very human-friendly, and tries to adhere to the 'natural language' approach of SQL which tries to avoid the use of constructs such as recursive brackets or semicolons to finish statements. Indenting and line breaks are not important, so definitions can be formatted for readability. Much of the definition can simply be omitted, and the report generator will fill in what it can. If the TABLE definition is left out, for example, then the report generator will internally generate one which has a column for each field returned by the query, and even has a header row. A general outline of a report definition looks like this: Copy to clipboard
|
Parameters | ||||||||||||||||||||||||||||||||||||||||
Query an ADOdb database and display results (does not work with PDO) Introduced in Tiki 3. Go to the source code Preferences required: wikiplugin_dbreport
This example uses a Wiki DSN to connect, and debugs the report definition. Copy to clipboard
Copy to clipboard
|
Keywords | |
Eight keywords are defined; SQL, PARAM, GROUP, TABLE, HEADER, ROW, FOOTER, CELL. They are case insensitive, but uppercase is encouraged for readability. Most commands take a sequence of parameters, terminated by the next keyword. Parameters come in five forms: Fields, Variables, Text, Styles, and Links
|
SQL Queries and Parameters | |
The query to be run by the database engine is defined by the SQL keyword, like so: Copy to clipboard
Parameters bind values to the '?' slots in a query.
The order of the parameter statements determines which slot they are bound to. Table fields cannot be used as SQL parameters, either directly or within strings, because no data has been obtained at the time of the binding. (The query hasn't run yet!) Attempts to use strings such as "[field1]" will bind the literal text (square brackets and all) to the parameter, which is probably not what you are after. SQL statements are processed by the database server, and must adhere to it's syntax, which can vary. Some common differences between server engines are:
Copy to clipboard
Double quotes were the original syntax, but it was discovered that escape sequences became unwieldy; Reporting definition strings are escaped, but so are literal strings in SQL statements. This double-escaping meant a backslash '\' within an SQL literal was encoded by four backslashes '\\\\' in the report definition. For example, an SQL statement that included quotes within strings like this: Copy to clipboard
Would have to be escaped as follows if using double quotes around the entire statement; Copy to clipboard
Curly braces allow SQL strings to be cut-and-pasted directly into the report definition without having to escape quotes or backslashes. Double-quoted SQL is retained as a 'backup' method in case some system does actually use brackets. |
Variables | |||||||||||||||||||||||||||||||||||||||||||||
Variables can come from three sources, in the following order of precedence. This order is chosen so that more 'intrinsic' variables cannot be overridden by more 'external' variables, while still allowing a useful mix.
|
Report Groups | |
Grouping (also called "Section Breaks" in other reporting systems) can be done based on one or more fields, and text may be generated for the title of each grouped section. Several levels of grouping can be done, each on many fields, but this really only affects the visual appearance of the report. Here are some examples: Copy to clipboard
Produces one group per unique combination of city and state. The order of the fields is irrelevant, but make sure they come first. Any fields specified after the text will be interpreted as part of the text. For multi-level display, something like this: Copy to clipboard
Copy to clipboard
Would create one level of grouping without any text heading, but will also put records from cities of the same name (but in different states) into the same group. |
Data Tables | |
For each unique group, a table is generated that will contain at least one record. (Otherwise the group would not be created by the data) This table can be given a style. Copy to clipboard
The table may also have headers and footers, which can be used to title columns or to show group totals. Fields can be used, not just text. The header will be generated using the same record as first row of the table, and the footer using the last record.
Copy to clipboard
Copy to clipboard
|
Styles and Formatting | |
Styles can be specified in two parts, which relates to the way HTML "style sheets" work. HTML elements can be given a "class", in which case their style information is found by looking in active stylesheets, and they can have "inline" style information (such as colours, borders, and margins) specified directly. Classes are the preferred method, since HTML pages are composed of hundreds (or thousands) of "tags" and having a short name attached to each is more efficient than having long strings of style information repeated over and over again, and the visual style of the page can be changed by using a different style sheet rather than re-writing all the HTML tags. |
Style Syntax | |
Style definitions in reports always begin with a ':' colon immediately followed (with no intervening whitespace) by a name which corresponds to a CSS class, and/or a string in {curly braces} which is used as inline style information. You can have whitespace inside the braces, but it's discouraged because it makes the code harder to read, and will also appear in the HTML. The following example shows a useful mixture of inline style information on the GROUP and TABLE, and style classes used for the ROW and CELL definitions that will generate efficient pages. Copy to clipboard
Remember that a GROUP with no actual fields or text will still produce a 'DIV' element in the output HTML which can be used to advantage, as in the example above. |
Report Keywords and HTML Elements | ||||||||||||||||||||||||||||||||||||||||
When using Cascading Style Sheets, it can be important to know how the various parts of the report are rendered into HTML, so that you know which "tag class" will be used for which report elements. The following table lists the translations;
Generally you should try to use style classes for ROW and CELL elements, as many of them will be generated for an average report. However, it's fine to specify inline CSS for the GROUP, TABLE, HEADERs and FOOTERs since relatively few of them are generated, and they tend to be the elements you want to control most with alignment, borders, and margins. |
Special Classes | ||||||||||||||||||||||||||||||||||||||||||||||||||
Nine style class names are treated specially when applied to Text, Fields and Variables. Instead of creating a text HTML element, they generate the named tag. These special classes do not apply to TABLE, GROUP, ROW, CELL, or Links keywords, since they must generate their own special tags.
You can also specify inline style for any of these classes, which is especially useful for the heading tags. This example turns the text into a level 1 heading, but also controls the leading margin. Copy to clipboard
However, this syntax does not allow you to set a class for the tag, only inline style. This is a limitation, but not a large one... if you have enough control over the stylesheet to declare heading tags with specific style classes, then you can just define new classes with the full style you want. |
Computed Style Names | |
Style classes and inline CSS don't have to be static strings. You can use variables or database fields to compose the style names. Indeed, you can use quite complicated SQL statements to determine what style to apply to individual rows. The following example shows a variety of styles composed from variables and fields; Copy to clipboard
Note that variables (from sources such as URL parameters) have to be enclosed in [square brackets] in the same way as within text strings. |
Multiple Classes | |
If you absolutely have to, you can specify multiple classes for an element by using an 'escaped space' (a space preceded by a single backslash) between the class names, which will translate through to the HTML attribute as a normal space; Copy to clipboard
Multiple classes are rarely used, but are legal CSS, and can be useful. They allow several 'subsets' of classes (perhaps one group that sets alignments, another group that sets colours, and a third which sets whitespace breaking) to be combined on a per-tag basis, rather than having to create style classes for every possible combination. They could even be used with computed styles to allow very tight control over field formatting, eg: Copy to clipboard
|
Web Links | |
Content in A common case is when you want to be able to click on a record and be taken to a detail page (or editor page) for that entry. The entire URL must be provided if you want an absolute link, (ie; starting with "http://") otherwise it will be interpreted by the browser as a relative link from the location of the current page, and will be appended to the current URL path by the browser in the normal way. For example: This would take you to the relevant page on another site when the group's title text was clicked; Copy to clipboard
Copy to clipboard
Copy to clipboard
Links may have multiple segments of text, with fields inside or outside the quotes. Multiple styles may be specified, but only the last one is applied. For example, the following Links are all equivalent: Copy to clipboard
The first example is the recommended form, because it is most clear that the style always applies to the whole link, and not just parts of it. |
URL Encoding | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
One subtle issue to note is the concept of URL encoding; some characters are not allowed in URLs, such as spaces. Other characters such as question marks, ampersands, plus and equals signs, and colons have special meanings. When building a URL from database fields you need to take care that the special characters are encoded appropriately. This is most important for text fields that might contain these special characters, but not so much for numeric fields, which end up with the same encoding whichever way you do it. Imagine you want to create links from database entries to search engines. The database table contains three fields, [Title], [Engine] and [Find]. You want to display the [Title] field in the report, and when you click on it you want to perform a search in some [Engine] for the [Find] term. Here's what the table could contain;
Copy to clipboard
So in conclusion, put fields into quoted strings when you want the field used 'as is' with no encoding, such as for complete URLs stored in a database. But in cases where you compose a URL that contains parameters, leave the parameter fields outside of the quotation marks so they are encoded. |
Useful Link Styles | |
It can sometimes be distracting to have every link in a table underlined, so don't forget about the "text-decoration" CSS property which can be set to "none". When creating clickable cells and rows, it's often useful to choose a CSS class that incorporates a 'hover' style and which changes the mouse pointer so that the users have some visual feedback. (Otherwise they won't necessarily know that the row is clickable unless they actually try it.) TikiWiki's 'odd' and 'even' row classes (usually) change the color of the row the user is hovering over, but should be extended to set the mouse pointer as in the following example; Copy to clipboard
Let's change the above example so that each cell becomes clickable rather than the whole row; Copy to clipboard
The [value] cell instead wraps a normal hyperlink around the text content. The text is coloured blue, gets an underline. But in normal circumstances the link would be confined to just the text, which could be a problem if the text content was an empty string, but we still wanted to click on it. (This is actually quite common with tables generated out of a database) This is why we want to use CSS to 'display' the link as a 'block', which causes it to expand to fill the entire cell. |
Examples | |
Finally, here is a complicated example that shows nearly every feature in use simultaneously, and in all their legal forms. (Unreal names are used for clarity) Copy to clipboard
Copy to clipboard
|
Developing a Report | |
There are two major parts to developing a report;
It's usually best to develop the SQL query first, and then think about the best way of arranging it on the screen later, once you can actually see some example data. |
Developing the SQL | |
The hardest part will probably be developing the SQL query. Most of the examples given have been simple "SELECT * FROM tablename" queries, but many real-world cases are quite complicated with multiple INNER JOINs, ON, WHERE, GROUP BY and ORDER BY clauses, concatenation of fields, and more. The SQL statement can easily be longer than the rest of the report definition. For performance reasons, it's best to only retrieve the fields that you intend to use in the report. While you can develop the SQL directly in the Wiki page editor, it may be better to do it with a proper database front-end, (Such as Microsoft Access, or phpMyAdmin) since it's likely to provide more help and better error messages. Once the query is working properly, just copy-and paste it into the report definition, but be careful of the following:
|
Developing the Display Definition | |
You do not actually have to specify a TABLE part of the report definition, in which case a simple 'default' table will be generated which has each field in it's own column, in the order that they come from the query. You can use this in combination with the debug parameter to the plugin to see the code for the TABLE section that the report generator creates from the data. For example, if we were to write the following Wiki code: Copy to clipboard
Copy to clipboard
|
Concatenating Fields into Text Strings | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Concatenating fields together for display can either be done in the SQL query, (Using a statement like "CONCAT(field1,field2) AS NewFieldName") or in the display part of the definition. (Using a Text string like "[Field1] [Field2]") and there are some subtleties you should be aware of, mostly to do with the whitespace between fields, and the behavior of the SQL CONCAT function, when fields have null values. For example, consider the common case where you need to concatenate a person's name out of three seperate fields; FirstName, MiddleNames, and Surname. Many people may not have any middle names, in which case this field could be NULL. We will also consider cases where the FirstName is also NULL, for various reasons. (This is more common than you think) Imagine we want, for each person, a line on the report that gives their full name followed by a full stop. Now consider the following three examples: Copy to clipboard
This looks right, but you need to know that the SQL CONCAT statement is defined to return NULL if any of it's parameters are NULL. So in cases where the person has no middle name, their entire name will come out blank! Not what we want at all! Although there are cases where this behavior is preferable, such as when adding prefix or suffix strings to a field, (like a dollar sign to money fields) and we want the entire field to remain blank if the involved field is null. Copy to clipboard
This is better, and we will see records for people who have NULL fields. However, we will also have some slight visual issues with extra spaces around fields that may have NULL values. Examine the following table of result fields and the concatenated string, where spaces in the output are represented with underscores:
Note how the spaces (represented as underscores) persist, even when some fields are null. In many cases this won't even be noticed, because extra whitespace in HTML pages is 'parsed away' by the browser, but this can lead to some interesting visual 'quirks', such as the last entry where a space will be visible between the "Nobody" and the trailing full stop. This issue becomes much more obvious if we were to use actual underscores, or other visible characters. To get perfect output, with no extra spaces, we instead should use the SQL CONCAT_WS function, like so: Copy to clipboard
CONCAT_WS (WS stands for "with separators") works slightly differently from CONCAT, in that the first parameter is used as the separator to use between fields, and NULL fields are skipped during the concatenation process. The text that is produced for our example data now looks like this:
Copy to clipboard
And here is what would be produced, given some example data:
Note how there are never extra underscore characters where they're not needed to separate names, and how the entire string is blank in cases where there is no Server. |
Security | |
When used correctly, security is quite good. Parameterized queries ensure that badly formed SQL due to funny requests can't happen. However, since this extension passes SQL strings to the database, hacks are possible such as malicious users changing the query to "DROP TABLE *" or worse, if they can edit the report definition.
|