Platon Technologies
neprihlásený Prihlásiť Registrácia
SlovakEnglish
open source software development oslavujeme 10 rokov vývoja otvoreného softvéru! Štvrtok, 19. september 2024

Súbor: [Platon] / phpMyEdit / doc / sgml / configuration.general.sgml (stiahnutie)

Revízia 1.60, Sun Sep 16 12:57:11 2007 UTC (17 years ago) by nepto


Zmeny od 1.59: +14 -2 [lines]

Added support for various language encodings
(default one is backward compatible and this
 will be changed later to UTF-8 for all languages)

<!-- $Platon: phpMyEdit/doc/sgml/configuration.general.sgml,v 1.59 2007-07-03 20:01:47 nepto Exp $ -->

<sect1 id="configuration.mysql-options">
<title id="configuration.mysql-options.title">Database connection</title>
<para>

Various options are configured near the top of the script, most notably the
database logon. For security reasons, you may want to copy/paste the logon
options to a separate, included file. 

</para>
<para>

MySQL logon options host name, user name, password, database, and table appear
in the following format. 

</para>
<para>

<example><title>Database connection options</title>
<programlisting><![CDATA[
$opts['hn'] = 'localhost';
$opts['un'] = 'username';
$opts['pw'] = 'password';
$opts['db'] = 'database';
$opts['tb'] = 'table';
]]></programlisting>
</example>

</para>
<para>

Recommended usage is, that the first four options shown above should be moved
to a separate, included file.

</para>
<para>

It is a rather common situation to use &name; inside larger project. To
prevent &name; from creating an additional persistent database connection,
supply the <varname>$opts['dbh']</varname> option. In the example below,
<varname>$your_project_db_handle</varname> represents a previously allocated
MySQL database handle. When <varname>$opts['dbh']</varname> is specified, the
first four options appearing above are ignored. 

</para>
<para>

<example><title>Supplying allocated connection</title>
<programlisting><![CDATA[
$opts['dbh'] = $your_project_db_handle;
]]></programlisting>
</example>

</para>
</sect1>

<sect1 id="configuration.unique-key">
<title id="configuration.unique-key.title">Unique key</title>
<para>

Assuming that 'id' is the name of the MySQL column selected as the unique
identifier when <filename>phpMyEditSetup.php</filename> script was run, the
key will appear in the script as: 

</para>
<para>

<example><title>Unique key definition</title>
<programlisting><![CDATA[
// Name of field which is the unique key
$opts['key'] = 'id';
]]></programlisting>
</example>

</para>
<para>

<important><para>

There were problems reported by &name; users regarding the usage of MySQL
reserved word as an unique key name (the example for this is "key" name). Thus
we recommend using another name of unique key. Usage of "id" or "ID"
names should be safe and good idea.

</para></important>

The column type for the unique numeric identifier should appear as: 

</para>
<para>

<example><title>Unique key type definition</title>
<programlisting><![CDATA[
// Type of key field (int, real, string, date, etc.)
$opts['key_type'] = 'int';
]]></programlisting>
</example>

</para>
<para>

The argument 'int' shown above indicates the column type is an integer. If the
column type was a date then 'date' would appear above instead of 'int'. Other
possible unique key types are 'real' or 'string'.

</para>

<important><para>

If you are using 'real' key type and some problems with record manipulaton have
occured, it is probably because your MySQL key datatype is 'float'. Comparsions
with this datatype is a common problem in most computer languages (including SQL),
because floating-point values are not exact values.  In most cases, changing
the MySQL datatype from 'float' to 'double' and preserving 'real' as &name; key type
should solve this problem.

</para>
<para>

For more information about this issue, read <ulink
url="http://www.mysql.com/doc/en/No_matching_rows.html">Solving Problems with No
Matching Rows</> chapter in the MySQL manual (in version 3.23.47 it was A.5.6).

</para></important>

</sect1>

<sect1 id="configuration.common-options">
<title id="configuration.common-options.title">Common options</title>

<bridgehead id="configuration.page-name">Page name</bridgehead>
<para>

The page name option defines the variable used for constructing page and form
links. If not defined, the default value <varname>$PHP_SELF</varname> will be
used.

<example><title>Setting up the page name</title>
<programlisting><![CDATA[
$opts['page_name'] = 'index.php';
]]></programlisting>
</example>

</para>

<bridgehead id="configuration.displayed-records">Displayed records</bridgehead>
<para>

This option controls the number of records displayed on the screen. Change the
argument for <varname>$opts['inc']</varname> in order to specify the maximum
number of rows to display at one time. The default is 15 rows. To display all
found records, specify a value of -1 (negative 1).

<example><title>Displayed records</title>
<programlisting><![CDATA[
$opts['inc'] = 20; // list 20 records per page

$opts['inc'] = -1; // list all found records
]]></programlisting>
</example>

</para>

<bridgehead id="configuration.multiple-selections">
Multiple selections</bridgehead>
<para>

This option affects the display of &lt;SELECT MULTIPLE&gt; boxes.  If the MySQL
column type is <!-- ENUM or -->"set", the number of lines displayed on multiple
selection filters is specified as:

<example><title>Multiple selections option</title>
<programlisting><![CDATA[
$opts['multiple'] = '4'; // default is 4
]]></programlisting>
</example>

</para>
<para>

Setting <varname>$opts['multiple']</varname> to a large number may adversely
affect the appearance of your form. Four (4) is the default.

</para>

<bridgehead id="configuration.page-elements">Special page elements</bridgehead>
<para>

There are some special page elements, that may be turned on or off by changing
<varname>$opts['display']</varname> array.

</para>
<para>

Setting the <varname>query</varname> or <varname>sort</varname> values to
<constant>true</constant> will display the current query or sort order near the
top of the table. To display the execution time of the query below the table,
change the <varname>time</varname> value from <constant>false</constant> to
<constant>true</constant>.  Setting <varname>sort</varname> to
<constant>true</constant> is very helpful in understanding how cumulative
sorting takes place. Setting <varname>num_pages</varname> or <varname>num_records</varname>
to <constant>false</constant> will stop displaying corresponding values next to buttons.
These values can be displayed also using <varname>$opts['buttons']</varname> configuration array.

</para>
<para>

To display these three page elements use: 

<example><title>Special page elements</title>
<programlisting><![CDATA[
$opts['display'] = array(
    'query' => true,
    'sort'  => true,
    'time'  => true
);
]]></programlisting>
</example>

</para>
<para>

There is also one special <varname>$opts['display']['tabs']</varname>
variable, which generally controls the TABs feature. For more information see
<xref linkend="configuration.tabs-feature"
endterm="configuration.tabs-feature.title"> section.

</para>
<para>

Another special variable is <varname>$opts['display']['form']</varname>, which
controls displaying &lt;FORM&gt; and &lt;/FORM&gt; HTML tags. If this variable
is not defined, its value is considered as true.  By default, form tags are
displayed.

</para>

<bridgehead id="configuration.urls">Images URL</bridgehead>
<para>

If graphic links are selected with navigation (for example by setting
<varname>$opts['navigation']</varname> to <constant>'GD'</constant>) then
<varname>$opts['url']</varname> can be used to specify the folder containing
images. The default image location is normally one folder (or directory level) below the
location of the <filename>phpMyEdit.class.php</filename> file.

<example><title>Images URL</title>
<programlisting><![CDATA[
$opts['url'] = array('images' => 'images/'); 
]]></programlisting></example>

</para>
<para>

Other URLs for another elements may be added into this array in future.

</para>

<bridgehead id="configuration.code-execution">Code execution</bridgehead>
<para>

Since version 4.0, &name; automatically starts its execution.
You can turn this feature off by setting: 

<example><title>Turning off default execution</title>
<programlisting><![CDATA[
$opts['execute'] = 0; 
]]></programlisting></example>

</para>
<para>

If variable <varname>$opts['execute']</varname> is not defined, its value is
considered as <constant>1</constant>.

</para>

</sect1>

<sect1 id="configuration.permission-options">
<title id="configuration.permission-options.title">Permission options</title>
<para>

Commonly used options include:

<simplelist type=horiz columns=2>
<member> &nbsp; <constant>A</constant></><member> -- add</>
<member> &nbsp; <constant>C</constant></><member> -- change</>
<member> &nbsp; <constant>P</constant></><member> -- copy</>
<member> &nbsp; <constant>V</constant></><member> -- view</>
<member> &nbsp; <constant>D</constant></><member> -- delete</>
<member> &nbsp; <constant>F</constant></><member> -- filter (search)</>
<member> &nbsp; <constant>I</constant></><member> -- initial sort suppressed</>
</simplelist>

</para>
<para>

Table listing is always enabled, since all actions are executed from this
screen. But it is possible to get specific behaviours without table listing
using appropriate &name; extension. See <xref endterm="extensions.title"
linkend="extensions"> chapter for more information.

</para>
<para>

Full privileges to manipulate records are configured as:

<example><title>Full permissions</title>
<programlisting><![CDATA[
$opts['options'] = 'ACPVDF';
]]></programlisting>
</example>

</para>
<para>

To deny the user the ability to delete records use: 

<example><title>Full permissions without delete</title>
<programlisting><![CDATA[
$opts['options'] = 'ACPVF';
]]></programlisting>
</example>

</para>
<para>

To limit the user to view, sort, list, or filter records use this: 

<example><title>Read only permissions</title>
<programlisting><![CDATA[
$opts['options'] = 'VFL'; 
]]></programlisting>
</example>

</para>
<para>

In a multi-user environment, it would be wise to only provide the system
administrator with the ability to delete records.

</para>
</sect1>

<sect1 id="configuration.sorting">
<title id="configuration.sorting.title">Sorting</title>
<para>

&name; offers powerful default and/or additional sorting capabilities via
<varname>$opts['sort_field']</varname> option. You can define the column name or
column field number that you'd prefer to sort on when the script is first loaded. To
get descending sort order, prefix the column name or field number with dash (-)
sign. Look at the following examples:

<example><title>Sort field option</title>
<programlisting><![CDATA[
$opts['sort_field'] = 'company'; // sorting according company field
$opts['sort_field'] = 3;         // sorting according 4th field
$opts['sort_field'] = '-id';     // descending sorting according id field
]]></programlisting>
</example>

</para>
<para>

Now, let's assume you want to sort your table according to the 'company' column, but
in addition also according to the 'department' column. So the default sort order
should be by company first, then department. For this purpose, you can set an array
with column names and/or field numbers to <varname>$opts['sort_field']</varname>
variable.

<example><title>Multiple sort fields</title>
<programlisting><![CDATA[
$opts['sort_field'] = array('company', 'department');
]]></programlisting>
</example>

</para>
<para>

Also note that &name;'s sorting feature is cumulative. This means, that if
default sort fields are specified and the user selects (clicks) to sort by
another column in table listing screen, the resulting screen will be sorted by
user selected column first and then by specified default sort fields.  Next
click on another sort column will again force to sort table by selected column
first. Previously selected fields or default ones will follow up in sorting
sequence.

</para>
<para>

This feature enables selecting more than one sort field on the fly. To clear
sort fields sequence and to initialize the default one, click on
<GUIlabel>Clear</GUIlabel> link in left upper corner. This link could be enabled
by setting <varname>$opts['display']['sort']</varname> to
<constant>true</constant>. See <xref linkend="configuration.page-elements"
endterm="configuration.page-elements"> subsection for more information. We
also recommend you to enable this option to see how this described sorting
feature works.

</para>
</sect1>

<sect1 id="configuration.navigation">
<title id="configuration.navigation.title">Navigation</title>
<para>

The style and location of navigational links is a combined setting. The
generated form will have various buttons, such as <GUIbutton>Next</GUIbutton>,
<GUIbutton>Prev</GUIbutton>, <GUIbutton>Save</GUIbutton>,
<GUIbutton>Cancel</GUIbutton>, etc. Their location relative to the table can be
changed. Button positions are:

<simplelist type=horiz columns=2>
<member> &nbsp; <constant>U</constant></><member> -- up / above table</>
<member> &nbsp; <constant>D</constant></><member> -- down / below table (default)</>
</simplelist>

</para>
<para>

Button possitions should be combined with navigation styles. The style of
navigational links may be text, buttons, or graphic images (icons):

<simplelist type=horiz columns=2>
<member> &nbsp; <constant>B</constant></><member> -- buttons (default)</>
<member> &nbsp; <constant>T</constant></><member> -- text links</>
<member> &nbsp; <constant>G</constant></><member> -- graphic links</>
</simplelist>

</para>
<para>

Possible combinations include:

<example><title>Navigation possibilities</title>
<programlisting><![CDATA[
$opts['navigation'] = 'DB'; // buttons below table
$opts['navigation'] = 'DT'; // text links below table
$opts['navigation'] = 'DG'; // graphics below table
$opts['navigation'] = 'UB'; // buttons above table
$opts['navigation'] = 'UT'; // text links above table
$opts['navigation'] = 'UG'; // graphics above table

$opts['navigation'] = 'UDBTG' // all navigations styles
]]></programlisting>
</example>

</para>
<para>

As you can see from the last example in box above, all navigation styles can be
mixed up together to fit your needs. There is no functionality difference
between navigation with graphic/text links and navigation using radio buttons
selection.

</para>

<para>

If you are not satisfied with order of buttons, or you want to remove certain buttons,
you can use <varname>$opts['buttons']</varname> option. In this option, you can specify
exact buttons to be displayed, even with custom ones. There are several common reasons
to remove some buttons: when having huge amount of pages, dropdown box creation is too long,
display save button only at the bottom of the page to force users to scroll through screeen before
adding a new record, and so on.

</para>

<para>

Buttons on phpMyEdit pages can be divided into several groups. These groups then specify keywords
which are used when declaring a button in <varname>$opts['buttons']</varname>. If an element in
<varname>$opts['buttons']</varname> is not matching a keyword, it is translated using language files.
If an element is an array, it is outputed as a custom button, as shown below.

<simplelist type=horiz columns=2>
<member> navigation </><member> &nbsp; <constant>first, <<, prev, <, next, >, last, >> </constant></>
<member> go to </><member> &nbsp; <constant>goto, goto_combo, goto_text </constant></>
<member> operation </><member> &nbsp; <constant>add, view, change, delete, copy </constant></>
<member> confirmation </><member> &nbsp; <constant>save, more, cancel </constant></>
<member> statistics </><member> &nbsp; <constant>current_page, total_pages, total_recs </constant></>
</simplelist>

Navigation and go to group can be used in list or filter mode to jump several pages ahead or back.
Operation group moves user to another mode, namely one of ACPDV. Confirmation buttons are used to
confirm actions in ACPDV. While cancel is self explanatory, save and more might be confusing.
Save is used to confirm action and return to L mode. More means confirming action and return to
current mode. Save button is usually displayed as Save, however in D mode it is as Delete and in A
mode as Add. More is displayed as either More or Apply. Keywords in the statistics group display
numbers as their names suggest.

</para>


<example><title>Default buttons</title>
<programlisting><![CDATA[
$opts['buttons']['L']['up'] = array('<<','<','add','view','change','copy','delete',
                                    '>','>>','goto','goto_combo');
$opts['buttons']['L']['down'] = $opts['buttons']['L']['up'];

$opts['buttons']['F']['up'] = array('<<','<','add','view','change','copy','delete',
                                    '>','>>','goto','goto_combo');
$opts['buttons']['F']['down'] = $opts['buttons']['F']['up'];

$opts['buttons']['A']['up'] = array('save','more','cancel');
$opts['buttons']['A']['down'] = $opts['buttons']['A']['up'];

$opts['buttons']['C']['up'] = array('save','more','cancel');
$opts['buttons']['C']['down'] = $opts['buttons']['C']['up'];

$opts['buttons']['P']['up'] = array('save', 'cancel');
$opts['buttons']['P']['down'] = $opts['buttons']['P']['up'];

$opts['buttons']['D']['up'] = array('save','cancel');
$opts['buttons']['D']['down'] = $opts['buttons']['D']['up'];

$opts['buttons']['V']['up'] = array('change','cancel');
$opts['buttons']['V']['down'] = $opts['buttons']['V']['up'];
]]></programlisting>
</example>

<para>

A button can be disabled for two reasons. A navigation button when there are no next or previous
pages or an operation button if certain operation is not permitted to the user. By default, all
disabled buttons are displayed and marked as disabled. If you do not want to show disabled buttons
at all, prepend '-' to keyword. If you want a disabled button to show as enabled, prepend '+'.
This will allow users to successfully push this button, however no meaningfull action will be taken.

<simplelist type=horiz columns=2>
<member> &nbsp; <constant>next</constant></><member> -- show next button and mark disabled if appropriate</>
<member> &nbsp; <constant>-next</constant></><member> -- do not show next button if disabled</>
</simplelist>

</para>

<para>

You may also specify custom buttons, which values can be used outside of phpMyEdit. The first way
to specify a custom button is to use phpMyEdit htmlSubmit method. In this way, value of this submit
button is translated using language files into user specified language. Possible configuration
is name, value, css class name, java script and disabled.

<simplelist type=horiz columns=2>
<member> &nbsp; <constant>name</constant></><member> -- name of the submit button</>
<member> &nbsp; <constant>value</constant></><member> -- value of submit button</>
<member> &nbsp; <constant>css</constant></><member> -- css class name</>
<member> &nbsp; <constant>js</constant></><member> -- any other string place within button tags, mostly java script</>
<member> &nbsp; <constant>disabled</constant></><member> -- 1 button is disabled, 0 button is not disabled</>
</simplelist>


Second way of declaring custom buttons, is to declare actuall html code of the button. Note that
using this method, any html entity can be outputted.

</para>

<example><title>Custom buttons</title>
<programlisting><![CDATA[
$opts['buttons']['V']['up'] = array(
    'change',
    'cancel',
    array('name' => 'pme_back', 'value' => 'Back to main menu',
          'css' => 'pme-backtomenu', 'disabled' => false),
    'Go to:',
    array('code' => '<SELECT><OPTION>....</OPTION></SELECT>'),
);
$opts['buttons']['V']['down'] = $opts['buttons']['V']['up'];
]]></programlisting>
</example>

<example><title>Buttons with large number of pages</title>
<programlisting><![CDATA[
$opts['buttons']['L']['up'] = array(
    '-<<',
    '-<',
    'Page',
    'goto_text',
    'of',
    'total_pages',
    '->',
    '->>');
);
$opts['buttons']['L']['down'] = $opts['buttons']['L']['up'];
$opts['display']['num_pages'] = false;
$opts['display']['num_records'] = false;
]]></programlisting>
</example>

</sect1>

<sect1 id="configuration.filters">
<title id="configuration.filters.title">Filters</title>
<para>

Table-level filter capability (if set) is included in the WHERE clause of any
generated SELECT statement. This gives you ability to work with a subset of data
from table.

</para>
<para>

<example><title>Filter examples</title>
<programlisting><![CDATA[
$opts['filters'] = 'column1 like "%11%" AND column2 < 17';

$opts['filters'] = 'section_id = 9';

$opts['filters'] = 'PMEtable0.sessions_count > 200';
]]></programlisting>
</example>

</para>
<para>

You can also pass an array to this option. If you do so, than array items are
put together with "AND" SQL statement.

</para>
<para>

When generating a query, &name; redefines/aliases the table names for easy
accessing of particular table fields in the main table and in the tables used
in JOIN clauses as well. The main table name is changed to <database
class=table>PMEtable0</>, tables used in JOIN clauses have their name like
<database class=table>PMEjoinN</> where <varname>N</> is JOIN table order.

</para>
<para>

We recommend that you look at the generated SQL queries in your MySQL log file in
order to know how database the table was aliased. Finally, the described
approach is needed only if you are accessing a field name which occurs in more
than one table of SQL query (thus MySQL cannot exactly determine what is
meant by "field_name").

</para>
<para>

For future development is planned an initialization like the following one.

<programlisting><![CDATA[
$opts['filters'] = array(
    'col_name_1' => 'value_1',
    'col_name_2' => 'value_2'
);
]]></programlisting>

The main advantage of this approach will be that <varname>col_name_1</> and
<varname>col_name_2</> fields are automatically considered as read-only on
display record pages with pre-set <constant>value_1</>, <constant>value_2</>
and without the need to enter them manually.

</para>
</sect1>

<sect1 id="configuration.triggers">
<title id="configuration.triggers.title">Triggers</title>
<bridgehead>Triggers overview</bridgehead>
<para>

Triggers provide advanced users with the ability to write their own PHP
scripts for such things as validating user input, and to have their code
executed at the appropriate time. Triggers are files that are included via
an&nbsp;<function>include()</function> statement and conditionally executed by
<filename>phpMyEdit.class.php</filename>. SQL triggers are included before or
after insert, update, or delete of record. FORM triggers are included before
displaying the form that will allow the corresponding operation, or after the
user canceled this form.

</para>
<para>

<itemizedlist spacing="compact">
<listitem><simpara>View form is related to the 'select' operation.</simpara></listitem>
<listitem><simpara>Add and Copy forms are related to the 'insert' operation</simpara></listitem>
<listitem><simpara>Edit form is related to the 'update' operation.</simpara></listitem>
<listitem><simpara>Delete form is related to the 'delete' operation.</simpara></listitem>
</itemizedlist>

</para>
<para>

For SQL triggers, the operation sequence is this: before, main, after.  If any
operation fails, not only should the next operation(s) not be executed, but
the previous ones are 'rolled back' as if they never happened.  If a database
is not able to do this, it is not 'transaction-safe'.

</para>
<para>

Triggers are risky in basic MySQL as there is no native transaction support.  It
is not transaction-safe by default. There are transaction-safe table types in
MySQL that can be conditionally built (see MySQL-Max), but &name; is currently
not set up to support real transactions. What that means is that if an
operation fails, the database may be left in an intermediate and invalid state.

</para>
<para>

The programmer must understand and accept these risks prior to using the &name;
triggers mechanism. If the triggers are used, they execute within the namespace
or scope of the &name; class.

</para>
<para>

Triggers must return <constant>true</constant> or <constant>false</constant>
to indicate success or failure.

</para>
<bridgehead>Triggers types</bridgehead>
<para>

There are following types of &name; triggers:

</para>
<para>

<itemizedlist>
<listitem><para>

'pre' triggers are usually used to check conditions before displaying
the operation's page. For example, users may be allowed to View all records but
can only Edit a subset of them. Another usage is to lock the record in
order to avoid other users to start to change it at the same time.

</para></listitem>
<listitem><para>

'before' triggers are usually used to verify conditions prior to
executing the main operation.
For example, they can be of some use for input validation.

</para></listitem>
<listitem><para>

'after' triggers are usually used to perform follow-up operations
after the main operation.  For example, to update secondary tables
to enforce referential integrity or to update aggregate tables.

</para></listitem>
<listitem><para>

'cancel' triggers are usually used to perform follow-up operations
after users cancel the form. For example, if a record is locked using a
'pre' triggers, then a 'cancel' trigger can unlock it.

</para></listitem>
</itemizedlist>

</para>
<para>

If 'pre' triggers fail, users are sent back to the list, except for the
'update' case, where users are sent back to view page if the pre-update
trigger fails.

</para>
<bridgehead>Trigger examples</bridgehead>
<para>

<example><title>Select triggers</title>
<programlisting><![CDATA[
// Before displaying the view page
$opts['triggers']['select']['pre']    = 'categories.TSP.inc';
// After canceling the view page
$opts['triggers']['select']['cancel'] = 'categories.TSC.inc';
]]></programlisting>
</example>

<example><title>Insert triggers</title>
<programlisting><![CDATA[
// Before displaying the add/copy page
$opts['triggers']['insert']['pre']    = 'categories.TIP.inc';
// After requesting save or more in the add/copy page
$opts['triggers']['insert']['before'] = 'categories.TIB.inc';
$opts['triggers']['insert']['after']  = 'categories.TIA.inc';
// After canceling the add/copy page
$opts['triggers']['insert']['cancel'] = 'categories.TIC.inc';
]]></programlisting>
</example>

<example><title>Update triggers</title>
<programlisting><![CDATA[
// Before displaying the edit page
$opts['triggers']['update']['pre']    = 'categories.TUP.inc';
// After requesting save or apply in the edit page
$opts['triggers']['update']['before'] = 'categories.TUB.inc';
$opts['triggers']['update']['after']  = 'categories.TUA.inc';
// After canceling the edit page
$opts['triggers']['update']['cancel'] = 'categories.TUC.inc';
]]></programlisting>
</example>

<example><title>Delete triggers</title>
<programlisting><![CDATA[
// Before displaying the delete page
$opts['triggers']['delete']['pre']    = 'categories.TDP.inc';
// After requesting delete in the delete page
$opts['triggers']['delete']['before'] = 'categories.TDB.inc';
$opts['triggers']['delete']['after']  = 'categories.TDA.inc';
// After canceling the delete page
$opts['triggers']['delete']['cancel'] = 'categories.TDC.inc';
]]></programlisting>
</example>

</para>
<para>

Please note that <varname>['select']['after']</varname> and
<varname>['select']['before']</varname> triggers currently do not exist.

</para>
<para>

In the following sample are steps during a View, Edit, Apply and Cancel
operation described. All involved triggers return <constant>true</constant>.

<itemizedlist spacing="compact">
<listitem><simpara>user starts from the list page</simpara></listitem>
<listitem><simpara>user asks to view a record</simpara></listitem>
<listitem><simpara><varname>['select']['pre']</varname> trigger is included (if defined)</simpara></listitem>
<listitem><simpara>if <constant>true</constant> is returned then continue, else go back to list page</simpara></listitem>

<listitem><simpara>user is now in the view page</simpara></listitem>
<listitem><simpara>user asks to edit the record</simpara></listitem>
<listitem><simpara><varname>['update']['pre']</varname> trigger is included (if defined)</simpara></listitem>
<listitem><simpara>if <constant>true</constant> is returned then continue, else go back to view page</simpara></listitem>

<listitem><simpara>user is now in the edit page</simpara></listitem>
<listitem><simpara>user makes some changes and asks to apply (save and continue)</simpara></listitem>
<listitem><simpara><varname>['update']['before']</varname> trigger is included (if defined)</simpara></listitem>
<listitem><simpara>if <constant>true</constant> is returned then continue, else, back to list without updating</simpara></listitem>
<listitem><simpara>record is updated in the database</simpara></listitem>
<listitem><simpara><varname>['update']['after']</varname> trigger is included (if defined)</simpara></listitem>
<listitem><simpara><varname>['update']['pre']</varname> trigger is included (if defined)</simpara></listitem>
<listitem><simpara>if <constant>true</constant> is returned then continue, else go back to view page</simpara></listitem>

<listitem><simpara>user is now back to the edit page</simpara></listitem>
<listitem><simpara>user makes some other changes but asks to cancel them</simpara></listitem>
<listitem><simpara><varname>['update']['cancel']</varname> trigger is included (if defined)</simpara></listitem>

<listitem><simpara>user is back to the list page</simpara></listitem>
</itemizedlist>

</para>
<bridgehead>Triggers variables</bridgehead>
<para>

In every trigger file you have available following usable variables. Some of
them affect only a particular action.

<simplelist type=horiz columns=2>
<member><varname>$this</varname></>
<member> &nbsp; object reference</>
<member><varname>$this->dbh</varname></>
<member> &nbsp; initialized MySQL database handle</>
<member><varname>$this->key</varname></>
<member> &nbsp; primary key name</>
<member><varname>$this->key_type</varname></>
<member> &nbsp; primary key type</>
<member><varname>$this->key_delim</varname></>
<member> &nbsp; primary key deliminator</>
<member><varname>$this->rec</varname></>
<member> &nbsp; primary key value (update and delete only)</>
<member><varname>$newvals</varname></>
<member> &nbsp; associative array of new values (update and insert only)</>
<member><varname>$oldvals</varname></>
<member> &nbsp; associative array of old values (update and delete only)</>
<member><varname>$changed</varname></>
<member> &nbsp; array of keys with changed values</>
</simplelist>

There are also other variables available. For example every class property can
be accessed using <varname>$this</> object reference. All variables occur in
'before' triggers as well as in 'after' triggers. 
Only class properties occurs in 'pre' and 'cancel' triggers currently.

</para>
<para>

It is recommended to use the <function>$this->myQuery()</function> method in order
to perform database queries for fetching additional data or doing inserts or
updates to other database tables.

</para>
<bridgehead>Chained triggers</bridgehead>
<para>

You may set several triggers for the same operation. This allows to isolate
code, to share more easily triggers between multiple calling scripts and to
reuse code produced by another &name; users.

</para>
<para>

The order triggers are executed in is important. It is set by the keys of the
chained triggers. As soon as one of the chained trigger fail, the overall
return value is set to <constant>false</constant>, and following triggers are
not executed. If none of chained triggers failed, then the return value is
<constant>true</constant>.

<example><title>Chained update before triggers</title>
<programlisting><![CDATA[
$opts['triggers']['update']['before'][1] = 'lock.TUA.inc';
$opts['triggers']['update']['before'][0] = 'check.TUB.inc';
]]></programlisting>
</example>

</para>
<para>

In this example, when the user clicks on the <GUIbutton>Save</GUIbutton>
button during editing a record, <filename>check.TUB.inc</filename> will be run
first. If it returns <constant>true</constant>, then
<filename>lock.TUB.inc</filename> will be run as well.  If one of these
triggers fails, update of the database won't be performed, just like if a
simple <varname>['update']['before']</varname> trigger failed. Note that
although the overall return value of 'cancel' triggers does not inluence
&name; behavior, the return value of each chained trigger is important.

</para>
</sect1>

<sect1 id="configuration.logging">
<title id="configuration.logging.title">Logging user actions</title>
<para>

You can log user actions into a special "changelog" table. You must have
table created and specified for &name; using the <varname>$opts['logtable']</>
option.

<example><title>Logging</title>
<programlisting><![CDATA[
$opts['logtable'] = 'changelog';
]]></programlisting>
</example>

<example><title>Log table schema</title>
<programlisting><![CDATA[
CREATE TABLE changelog (
    updated    timestamp(14)  default NULL,
    user       varchar(255)   default NULL,
    host       varchar(255)   default NULL,
    operation  varchar(255)   default NULL,
    tab        varchar(255)   default NULL,
    rowkey     varchar(255)   default NULL,
    col        varchar(255)   default NULL,
    oldval     blob           default NULL,
    newval     blob           default NULL
);
]]></programlisting>
</example>

</para>
<para>

&name; provides also the possibility of notifying about performed user actions by
sending informational e-mail. This feature configuration is done via
<varname>$opts['notify']</> array with following variables notation. Note that
on every place where one e-mail address should be written, it is possible to
have array of multiple e-mail addresses there. This feature is provided for
informing more than one user about particular performed action.

<simplelist type=horiz columns=2>
<member><varname>$opts['notify']['from']</></><member> &nbsp; sender envelope e-mail address (webmaster@SERVER_NAME by default)</>
<member><varname>$opts['notify']['prefix']</></><member> &nbsp; prefix of e-mail messages subject (no prefix by default)</>
<member><varname>$opts['notify']['wrap']</></><member> &nbsp; maximum width of e-mail message body (by default <constant>72</> will be used)</>
<member><varname>$opts['notify']['insert']</></><member> &nbsp; e-mail address for insert action notification</>
<member><varname>$opts['notify']['update']</></><member> &nbsp; e-mail address for update action notification</>
<member><varname>$opts['notify']['delete']</></><member> &nbsp; e-mail address for delete action notification</>
<member><varname>$opts['notify']['all']</></><member> &nbsp; e-mail address for all actions notification</>
</simplelist>

</para>
<para>

In both cases, changelog table and e-mail notyfing are values of "user"
extracted from the variables in following order:
<varname>$_SERVER['REMOTE_USER']</>,
<varname>$_SERVER['REMOTE_USER']</> and global variable
<varname>$REMOTE_USER</>. Similary "host" variable is checked in
<varname>$_SERVER['REMOTE_ADDR']</>, than in
<varname>$_SERVER['REMOTE_ADDR']</> and at the end in global variable
<varname>$REMOTE_ADDR</>.

</para>
</sect1>

<sect1 id="configuration.languages">
<title id="configuration.languages.title">Languages</title>
<para>

The default language setting is the user's web browser language setting. Use
it if possible. The following example forces the English language version, and
the last forces the Slovak language version.

<example><title>Languages selection</title>
<programlisting><![CDATA[
// client language (default)
$opts['language'] = $_SERVER['HTTP_ACCEPT_LANGUAGE'];

$opts['language'] = 'EN'; // forces english language
$opts['language'] = 'SK-UTF8'; // slovak language in UTF-8 encoding
]]></programlisting>
</example>

</para>
<para>

Available languages are:

<simplelist type=horiz columns=2>
<member><constant>CZ</constant></><member> &nbsp; czech</>
<member><constant>DE</constant></><member> &nbsp; german (standard)</>
<member><constant>DK</constant></><member> &nbsp; danish</>
<member><constant>EL</constant></><member> &nbsp; greek (hellenic)</>
<member><constant>EN</constant></><member> &nbsp; english</>
<member><constant>EN-US</constant></><member> &nbsp; english (United States)</>
<member><constant>ES</constant></><member> &nbsp; spanish</>
<member><constant>ES-AR</constant></><member> &nbsp; spanish (argentinian)</>
<member><constant>ES-MX</constant></><member> &nbsp; spanish (mexican)</>
<member><constant>EU</constant></><member> &nbsp; basque</>
<member><constant>FR</constant></><member> &nbsp; french (standard)</>
<member><constant>ID</constant></><member> &nbsp; indonesian</>
<member><constant>IT</constant></><member> &nbsp; italian (standard)</>
<member><constant>JP</constant></><member> &nbsp; japanese</>
<member><constant>NL</constant></><member> &nbsp; dutch (standard)</>
<member><constant>PL</constant></><member> &nbsp; polish</>
<member><constant>PT</constant></><member> &nbsp; portuguese (standard)</>
<member><constant>PT-BR</constant></><member> &nbsp; portuguese (brazilian)</>
<member><constant>RU</constant></><member> &nbsp; russian</>
<member><constant>SE</constant></><member> &nbsp; swedish</>
<member><constant>SK</constant></><member> &nbsp; slovak</>
<member><constant>TR</constant></><member> &nbsp; turkish</>
<member><constant>ZH</constant></><member> &nbsp; chinese (traditional)</>
<member><constant>ZH-SG</constant></><member> &nbsp; chinese (Singapore)</>
</simplelist>

</para>
<para>

Language codes are based on ISO-3166 standard, which is available on many
places, for example <ulink url="http://www.samspade.org/d/iso3166.html">here</>.

</para>
<para>

You can append encoding strings to your language, such as
<constant>-UTF8</constant> or <constant>-LATIN2</constant>. If no encoding
is specified, backward compatible default one will be used.

<warning><simpara>
Default encoding will be switched in next release to
<constant>UTF-8</constant> in every available language.
</simpara></warning>

</para>
</sect1>

<sect1 id="configuration.cgi-variables">
<title id="configuration.cgi-variables.title">CGI variables</title>
<bridgehead id="configuration.cgi-variables-using">Using CGI variables</bridgehead>
<para>

You can optionally append or overwrite individual variables returned from the
CGI environment (GET/POST HTTP protocol data). Use these two arrays for this
purpose, where array key means CGI variable name, and array value means CGI
variable value.

</para>
<para>

This will activate the search filter on script initialization. However, it is
still possible to turn it off by explicit click on <GUIbutton>Hide</> or
<GUIbutton>Clear</> button.

<example><title>CGI variables appending</title>
<programlisting><![CDATA[
$opts['cgi']['append']['PME_sys_fl'] = 1;
]]></programlisting></example>

</para>
<para>

The next example shows how to cause descending sorting according first field in all
cases. Because <varname>['overwrite']</varname> is used, sorting column cannot
be altered by the user by clicking on column heading. 

<example><title>CGI variables overwriting</title>
<programlisting><![CDATA[
$opts['cgi']['overwrite']['PME_sys_sfn'] = '-0';
]]></programlisting></example>

</para>
<para>

Using the <varname>$opts['cgi']['persist']</> option you can tell &name; names and
values of CGI variables which should be persistent during various pages
reloading and serving. They will be included into all links and also into all
forms as appropriate hidden inputs. This feature is provided especially for
advanced and experienced users using &name; in their medium-size and large-size
projects. If you do not understand what does this thing do, feel free to skip
it. You will surely do not need it.

<example><title>Persistent CGI variables</title>
<programlisting><![CDATA[
$opts['cgi']['persist'] = array(
        'article_id' => $article_id,
        'session_id' => $SESSION_ID
        );
]]></programlisting></example>

</para>
<bridgehead id="configuration.cgi-variables-prefixing">Prefixing CGI variables</bridgehead>
<para>

The type of performed operation such as Add, Change, Delete and so on, is
passed using a CGI variable named <varname>operation</>. When passed through a
link, for example when <varname>$opts['navigation']</varname> is set
to&nbsp;<constant>'G'</constant>&nbsp;or&nbsp;<constant>'T'</constant>, the
value is an untranslated label prefixed with <constant>PME_op_</constant>.
This prefix can be changed by setting the
<varname>$opts['cgi']['prefix']['operation']</varname> variable in the calling
script.

<example><title>Custom prefix for operation links</title>
<programlisting><![CDATA[
$opts['cgi']['prefix']['operation'] = 'op-prefix-';
]]></programlisting></example>

</para>
<para>

If you already use in your project some CGI variables used internally by &name;,
like '<varname>operation</>, you may want to prefix &name;'s variables to avoid
collision. For the same reason, you may want to prefix the names of input
fields.

<example><title>Custom name prefix for CGI variables</title>
<programlisting><![CDATA[
$opts['cgi']['prefix']['sys'] = 'sys_prefix_';
$opts['cgi']['prefix']['data'] = 'data_prefix_';
]]></programlisting></example>

</para>
</sect1>

<sect1 id="configuration.js-and-dhtml">
<title id="configuration.js-and-dhtml.title">Javascript and DHTML</title>
<para>

CGI <varname>sys</varname> and <varname>data</varname> name prefixing may
especially be useful if you want to display two instance of &name; on the same
page. But you will require to prefix Javascript and DHTML tags as well, to make &name;
forms truely independant.

</para>
<para>

Javascript functions are default prefixed by <constant>PME_js_</constant>
string. DHTML ID tags are defaultly prefixed by
<constant>PME_dhtml_</constant> string. You may change this using the syntax
below.

<example><title>Custom name prefix for JS and DHTML</title>
<programlisting><![CDATA[
$opts['js']['prefix'] = 'js_prefix_';
$opts['dhtml']['prefix'] = 'dhtml_prefix_';
]]></programlisting></example>

</para>
</sect1>

<sect1 id="configuration.css">
<title id="configuration.css.title">CSS classes policy</title>
<para>

CSS classes policy in &name; is one from the most complicated and complex
features. The goal is to reach almost any possible classification of HTML
elements with the possibility to simplify classification to lower number of
classes. 

</para>
<para>

The &name; CSS class schema is displayed here:

<example><title>CSS class name schema</title>
<programlisting><![CDATA[
<prefix>-<element>-<page_type>-<position>-<divider>-<postfix>
]]></programlisting></example>
</para>
<para>

Particular parts are described here:

<itemizedlist spacing=compact>
<listitem><para>
The <varname>prefix</> part is straighforward. Every &name; CSS class has a user
configurable prefix. It can be empty.
</para></listitem>
<listitem><para>
The <varname>element</> represents the name or type of element.  The examples
are <varname>form</>, <varname>row</>, <varname>value</>, <varname>input</>
and others.
</para></listitem>
<listitem><para>
In order to distinguish between different types of pages there is a
<varname>page_type</>. The possible values for this part are
<varname>add</>, <varname>view</>, <varname>change</>, <varname>copy</>,
<varname>delete</>.  This part is empty for table listing and table filtering
pages.
</para></listitem>
<listitem><para>
There are also some elements, which occur on the top and on the bottom of
page as well. For this matter there is <varname>position</> part present with
possible values <varname>up</> and <varname>down</>.
</para></listitem>
<listitem><para>
The <varname>divider</> aim is to provide difference between even and odd
table listing rows. This part, if present, is always numeric with values
starting from <constant>0</>.
</para></listitem>
<listitem><para>
At the end of CSS class name is <varname>postfix</>. This part is related to a
particular field. Every field can have its own postfix. See field's <xref
linkend="configuration.fields.css" endterm="configuration.fields.css"> for
more information.
</para></listitem>
<listitem><para>
The default separator between parts is dash (<constant>-</>) and can be
changed if desired.
</para></listitem>
</itemizedlist>

</para>
<para>

CSS class names configuration is handled via <varname>$opts['css']</>
associative array. Here are possible configuration options related to this
issue.

</para>
<para>

<simplelist type=horiz columns=2>
<member><varname>$opts['css']['prefix']</></>
<member> &nbsp; prefix of every &name; CSS class (<constant>pme</> by default)</>
<member><varname>$opts['css']['page_type']</></>
<member> &nbsp; if page type should occur in class name (disabled by default)</>
<member><varname>$opts['css']['position']</></>
<member> &nbsp; if position on the page should occur in class name (disabled by default)</>
<member><varname>$opts['css']['divider']</></>
<member> &nbsp; how many list table rows should have their own number before
starting counting again from <constant>0</> (by default <constant>2</>; value
of <constant>-1</> means every row has its own number and value of
<constant>0</> means disabled)</>
<member><varname>$opts['css']['separator']</></>
<member> &nbsp; separator between CSS class name parts (dash <constant>-</> by default)</>
</simplelist>

</para>
<para>

For concrete names of CSS classes look into HTML source code of your generated
page. In the following box are examples of how CSS class names may appear.
However your CSS class names can differ according to your fields and
configuration respectively.

<example><title>CSS class name examples</title>
<programlisting><![CDATA[
pme-navigation-up
pme-row-0
pme-cell-DateTime
pme-cancel-view
pme-input-change
pme-key-ArticleID
]]></programlisting></example>

</para>
</sect1>


Platon Group <platon@platon.sk> http://platon.sk/
Copyright © 2002-2006 Platon Group
Stránka používa redakčný systém Metafox
Na začiatok